Pārlūkot izejas kodu

feat: 新增找人脉页面

cuiyalong 9 mēneši atpakaļ
vecāks
revīzija
627bd6f1ab

+ 15 - 0
apps/bigmember_pc/src/api/modules/bi.js

@@ -24,3 +24,18 @@ export function getPropertyFilters() {
     method: 'post'
   })
 }
+
+export function getNetworkManageMonitorList(data) {
+  return request({
+    url: '/jyapi/networkManage/pr/monitor/list',
+    method: 'post',
+    data
+  })
+}
+export function getNetworkManageCollectionList(data) {
+  return request({
+    url: '/jyapi/networkManage/pr/collect/list',
+    method: 'post',
+    data
+  })
+}

+ 323 - 263
apps/bigmember_pc/src/components/article-item/ArticleItem.vue

@@ -8,141 +8,158 @@
       'style-for-bidding': config.bidding
     }"
   >
-    <div class="article-item-header">
-      <input
-        v-if="config.collect"
-        @change="changeCheck($event)"
-        @click.stop
-        class="custom-checkbox title-text-checkbox"
-        name="bid-list"
-        type="checkbox"
-        :dataid="article._id"
-      />
-      <div class="a-i-con">
-        <div class="content-item">
-          <div
-            v-html="calcTitle"
-            class="a-i-left visited-hd"
-            :class="(config.push || config.bidding) ? 'ellipsis-3' : 'ellipsis'"
-            @click="onClick"
-          ></div>
+    <div class="list-item-left">
+      <slot name="prefix"></slot>
+    </div>
+    <div class="list-item-content">
+      <div class="article-item-header">
+        <input
+          v-if="config.collect"
+          @change="changeCheck($event)"
+          @click.stop
+          class="custom-checkbox title-text-checkbox"
+          name="bid-list"
+          type="checkbox"
+          :dataid="article._id"
+        />
+        <div class="a-i-con">
+          <div class="content-item">
+            <div
+              v-html="calcTitle"
+              class="a-i-left visited-hd"
+              :class="config.push || config.bidding ? 'ellipsis-3' : 'ellipsis'"
+              @click="onClick"
+            ></div>
+          </div>
+          <div class="time-container">
+            <span class="el-icon-jy-time" v-if="!config.gray"></span>
+            <span class="time-text">
+              <slot name="right-time">{{
+                dateFromNow(article.publishtime * 1000) ||
+                dateFromNow(article.publishTime * 1000)
+              }}</slot>
+            </span>
+          </div>
         </div>
-        <div class="time-container">
-          <span class="el-icon-jy-time" v-if="!config.gray"></span>
-          <span class="time-text">
-            <slot name="right-time">{{
-              dateFromNow(article.publishtime * 1000) || dateFromNow(article.publishTime * 1000)
-            }}</slot>
+      </div>
+      <div
+        v-if="config.detail && article.detail && calcDetail"
+        class="a-i-detail ellipsis"
+        v-html="calcDetail"
+      ></div>
+      <div class="a-i-right">
+        <div class="tags">
+          <span
+            class="tag tag-user"
+            v-if="
+              article.site === '剑鱼信息发布平台' ||
+              article.spidercode === 'a_jyxxfbpt_gg' ||
+              article.spiderCode === 'a_jyxxfbpt_gg'
+            "
+            >业主委托项目</span
+          >
+          <span class="tag tag-own" v-if="buySubject && article.source === 1"
+            >个人订阅</span
+          >
+          <span class="tag tag-ent" v-if="buySubject && article.source === 2"
+            >企业自动分发</span
+          >
+          <span class="tag tag-ent" v-if="buySubject && article.source === 3"
+            >企业手动分发</span
+          >
+          <span
+            class="tag"
+            v-if="calcArea"
+            :class="{
+              'tag-handle': tagClickList.includes('area') && article.areaUrl
+            }"
+            @click.stop="tagClick('area')"
+          >
+            {{ calcArea }}</span
+          >
+          <span
+            class="tag orange"
+            :class="{
+              'tag-handle':
+                tagClickList.includes('subtype') && article.subtypeUrl
+            }"
+            v-if="article.type || article.subtype"
+            @click.stop="tagClick('subtype')"
+          >
+            {{ article.type || article.subtype }}
+          </span>
+          <span class="tag green" v-if="calcBuyerclass">{{
+            article.buyerclass || article.buyerClass
+          }}</span>
+          <span class="tag dpink" v-if="calcBudget && calcBudget !== '0元'">
+            {{ calcBudget }}
           </span>
+          <span
+            v-if="config.gray && (article.ca_fileExists || article.fileExists)"
+            class="haveFile"
+            >有附件</span
+          >
         </div>
-      </div>
-    </div>
-    <div
-      v-if="config.detail && article.detail && calcDetail"
-      class="a-i-detail ellipsis"
-      v-html="calcDetail"
-    ></div>
-    <div class="a-i-right">
-      <div class="tags">
-        <span
-          class="tag tag-user"
-          v-if="
-            article.site === '剑鱼信息发布平台' ||
-            article.spidercode === 'a_jyxxfbpt_gg'
-          "
-          >业主委托项目</span
-        >
-        <span class="tag tag-own" v-if="buySubject && article.source === 1"
-          >个人订阅</span
-        >
-        <span class="tag tag-ent" v-if="buySubject && article.source === 2"
-          >企业自动分发</span
-        >
-        <span class="tag tag-ent" v-if="buySubject && article.source === 3"
-          >企业手动分发</span
-        >
-        <span class="tag"
-              v-if="calcArea"
-              :class="{'tag-handle': tagClickList.includes('area') && article.areaUrl}"
-              @click.stop="tagClick('area')">
-          {{ calcArea }}</span>
-        <span class="tag orange"
-              :class="{'tag-handle': tagClickList.includes('subtype') && article.subtypeUrl}"
-              v-if="article.type || article.subtype"
-              @click.stop="tagClick('subtype')">
-          {{article.type || article.subtype }}
-        </span>
-        <span
-          class="tag green"
-          v-if="calcBuyerclass"
-          >{{ article.buyerclass || article.buyerClass }}</span
-        >
-        <span class="tag dpink" v-if="calcBudget && calcBudget !== '0元'">
-          {{ calcBudget }}
-        </span>
-        <span v-if="config.gray && (article.ca_fileExists || article.fileExists)" class="haveFile"
-          >有附件</span
-        >
-      </div>
-      <div style="display: flex; align-items: center">
-        <el-popover
-          popper-class="statusPopover"
-          placement="left"
-          :visible-arrow="false"
-          :append-to-body="false"
-          v-if="vt === 'q'"
-          @show="setShow"
-          trigger="hover"
-        >
-          <el-table maxHeight="288px" :border="true" :data="gridData">
-            <el-table-column
-              align="center"
-              width="88"
-              prop="name"
-              label="员工姓名"
-            ></el-table-column>
-            <el-table-column
-              align="center"
-              width="120"
-              prop="phone"
-              label="手机号"
-            ></el-table-column>
-            <!-- 信息来源 -->
-            <el-table-column label="信息来源" align="center" width="112">
-              <template slot-scope="scope">
-                {{ formatSource(scope.row.source) || '-' }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              class-name="pushTime"
-              align="center"
-              width="136"
-              prop="date"
-              label="推送时间"
-            ></el-table-column>
-            <el-table-column
-              align="center"
-              width="96"
-              prop="isvisit"
-              label="查看状态"
-            ></el-table-column>
-            <el-table-column
-              class-name="viewTime"
-              align="center"
-              width="136"
-              prop="visittime"
-              label="最近一次查看时间"
-            ></el-table-column>
-          </el-table>
-          <span slot="reference" class="view-status">查看状态</span>
-        </el-popover>
-        <slot name="right-handle-container"></slot>
-        <!-- 参标-->
-        <div
-          v-if="config.joinBid && ('joinBid' in article)"
-          class="join-bid"
-          @click.prevent.stop="joinBidChange"
-        >
+
+        <div style="display: flex; align-items: center">
+          <el-popover
+            popper-class="statusPopover"
+            placement="left"
+            :visible-arrow="false"
+            :append-to-body="false"
+            v-if="vt === 'q'"
+            @show="setShow"
+            trigger="hover"
+          >
+            <el-table maxHeight="288px" :border="true" :data="gridData">
+              <el-table-column
+                align="center"
+                width="88"
+                prop="name"
+                label="员工姓名"
+              ></el-table-column>
+              <el-table-column
+                align="center"
+                width="120"
+                prop="phone"
+                label="手机号"
+              ></el-table-column>
+              <!-- 信息来源 -->
+              <el-table-column label="信息来源" align="center" width="112">
+                <template slot-scope="scope">
+                  {{ formatSource(scope.row.source) || '-' }}
+                </template>
+              </el-table-column>
+              <el-table-column
+                class-name="pushTime"
+                align="center"
+                width="136"
+                prop="date"
+                label="推送时间"
+              ></el-table-column>
+              <el-table-column
+                align="center"
+                width="96"
+                prop="isvisit"
+                label="查看状态"
+              ></el-table-column>
+              <el-table-column
+                class-name="viewTime"
+                align="center"
+                width="136"
+                prop="visittime"
+                label="最近一次查看时间"
+              ></el-table-column>
+            </el-table>
+            <span slot="reference" class="view-status">查看状态</span>
+          </el-popover>
+          <slot name="right-handle-container"></slot>
+          <!-- 参标-->
+          <div
+            v-if="config.joinBid && 'joinBid' in article"
+            class="join-bid"
+            @click.prevent.stop="joinBidChange"
+          >
             <i
               class="j-self-icon"
               :class="
@@ -150,121 +167,141 @@
               "
             ></i>
             <span>{{ article.joinBid ? '终止参标' : '参标' }}</span>
-        </div>
-        <!-- 收藏-->
-        <div
-          class="right-actions"
-          v-if="config.collect"
-          @click.stop="collectChange($event)"
-        >
-          <i
-            class="icon-collect"
-            :class="{ checked: article.collection }"
-            :dataid="article._id"
-          ></i>
-          <span name="right-action" style="font-size: 14px; margin-left: 4px">{{
-            article.collection ? '已收藏' : '收藏'
-          }}</span>
+          </div>
+          <!-- 收藏-->
+          <div
+            class="right-actions"
+            v-if="config.collect"
+            @click.stop="collectChange($event)"
+          >
+            <i
+              class="icon-collect"
+              :class="{ checked: article.collection }"
+              :dataid="article._id"
+            ></i>
+            <span
+              name="right-action"
+              style="font-size: 14px; margin-left: 4px"
+              >{{ article.collection ? '已收藏' : '收藏' }}</span
+            >
+          </div>
         </div>
       </div>
-    </div>
-    <div class="list-detail" v-show="showDetailModel">
-      <p
-        class="l-d-item"
-        v-if="article.buyer || article.buyerTel || article.budget"
-      >
-        <span v-if="article.buyer">
-          <i class="l-d-item-label">采购单位:</i>
-          <em
-            v-for="(buyer, b) in formatBuyer(article.buyer)"
-            :key="b"
-            @click="goPortrayal('buyerDesc', buyer)"
-            class="highlight-text pointer"
-          >
-            {{ buyer }}
-            <em v-if="b != formatBuyer(article.buyer).length - 1">、</em>
-          </em>
-        </span>
-        <span v-if="article.buyerTel">
-          <i class="l-d-item-label">采购单位联系方式:</i>
-          {{ article.buyerPerson }}
-          <em v-if="article.buyerPerson">,</em>
-          {{ article.buyerTel }}
-          <em
-            class="more-tel"
-            v-if="article.buyerTel"
-            @click="goPortrayal('buyerDesc', article.buyer, 'contact')"
-            >获取更多</em
-          >
-        </span>
-        <span v-if="article.budget">
-          <i class="l-d-item-label">预算金额:</i>
-          {{ moneyUnit(article.budget) }}
-        </span>
-      </p>
-      <p class="l-d-item" v-if="article.agency || article.agencyTel">
-        <span v-if="article.agency">
-          <i class="l-d-item-label">代理机构:</i>
-          {{ article.agency }}
-        </span>
-        <span v-if="article.agencyTel">
-          <i class="l-d-item-label">代理机构联系方式:</i>
-          {{ article.agencyPerson }}<em v-if="article.agencyPerson">,</em
-          >{{ article.agencyTel }}</span
+      <div class="list-detail" v-show="showDetailModel">
+        <p
+          class="l-d-item"
+          v-if="article.buyer || article.buyerTel || article.budget"
         >
-      </p>
-      <p
-        class="l-d-item"
-        v-if="article.winner || article.winnerTel || article.bidAmount"
-      >
-        <span v-if="article.winnerInfo && article.winnerInfo.length > 0">
-          <i class="l-d-item-label">中标单位:</i>
-          <em
-            v-for="(w, i) in article.winnerInfo"
-            :key="w.winnerId"
-            @click="goPortrayal('entDesc', w.winnerId)"
-            class="highlight-text pointer"
-          >
-            {{ w.winner }}
-            <em v-if="i != article.winnerInfo.length - 1" :key="i + '_1'"
-              >、</em
+          <span v-if="article.buyer">
+            <i class="l-d-item-label">采购单位:</i>
+            <em
+              v-for="(buyer, b) in formatBuyer(article.buyer)"
+              :key="b"
+              @click="goPortrayal('buyerDesc', buyer)"
+              class="highlight-text pointer"
+            >
+              {{ buyer }}
+              <em v-if="b != formatBuyer(article.buyer).length - 1">、</em>
+            </em>
+          </span>
+          <span v-if="article.buyerTel">
+            <i class="l-d-item-label">采购单位联系方式:</i>
+            {{ article.buyerPerson }}
+            <em v-if="article.buyerPerson">,</em>
+            {{ article.buyerTel }}
+            <em
+              class="more-tel"
+              v-if="article.buyerTel"
+              @click="goPortrayal('buyerDesc', article.buyer, 'contact')"
+              >获取更多</em
             >
-          </em>
-        </span>
-        <span v-if="article.winnerTel">
-          <i class="l-d-item-label">中标单位联系方式:</i>
-          {{ article.winnerPerson }}
-          <em v-if="article.winnerPerson">,</em>
-          {{ article.winnerTel }}
-          <em
-            class="more-tel"
-            v-if="article.winnerInfo && article.winnerInfo.length === 1"
-            @click="goPortrayal('entDesc', article.winnerInfo[0].winnerId, 'contact')"
-            >获取更多</em
+          </span>
+          <span v-if="article.budget">
+            <i class="l-d-item-label">预算金额:</i>
+            {{ moneyUnit(article.budget) }}
+          </span>
+        </p>
+        <p class="l-d-item" v-if="article.agency || article.agencyTel">
+          <span v-if="article.agency">
+            <i class="l-d-item-label">代理机构:</i>
+            {{ article.agency }}
+          </span>
+          <span v-if="article.agencyTel">
+            <i class="l-d-item-label">代理机构联系方式:</i>
+            {{ article.agencyPerson }}<em v-if="article.agencyPerson">,</em
+            >{{ article.agencyTel }}</span
           >
-        </span>
-        <span v-if="article.bidAmount">
-          <i class="l-d-item-label">中标金额:</i>
-          {{ moneyUnit(article.bidAmount) }}
-        </span>
-      </p>
-      <p
-        class="l-d-item"
-        v-if="article.signendTime || article.bidendTime || article.bidEndTime || article.bidOpenTime"
-      >
-        <span v-if="article.signendTime">
-          <i class="l-d-item-label">报名截止日期:</i>
-          {{ dateFromNow(article.signendTime * 1000) }}
-        </span>
-        <span v-if="article.bidendTime || article.bidEndTime">
-          <i class="l-d-item-label">投标截止日期:</i>
-          {{ dateFromNow(article.bidendTime * 1000) || dateFromNow(article.bidEndTime * 1000) }}
-        </span>
-        <span v-if="article.bidOpenTime">
-          <i class="l-d-item-label">开标日期:</i>
-          {{ dateFromNow(article.bidOpenTime * 1000) }}
-        </span>
-      </p>
+        </p>
+        <p
+          class="l-d-item"
+          v-if="article.winner || article.winnerTel || article.bidAmount"
+        >
+          <span v-if="article.winnerInfo && article.winnerInfo.length > 0">
+            <i class="l-d-item-label">中标单位:</i>
+            <em
+              v-for="(w, i) in article.winnerInfo"
+              :key="w.winnerId"
+              @click="goPortrayal('entDesc', w.winnerId)"
+              class="highlight-text pointer"
+            >
+              {{ w.winner }}
+              <em v-if="i != article.winnerInfo.length - 1" :key="i + '_1'"
+                >、</em
+              >
+            </em>
+          </span>
+          <span v-if="article.winnerTel">
+            <i class="l-d-item-label">中标单位联系方式:</i>
+            {{ article.winnerPerson }}
+            <em v-if="article.winnerPerson">,</em>
+            {{ article.winnerTel }}
+            <em
+              class="more-tel"
+              v-if="article.winnerInfo && article.winnerInfo.length === 1"
+              @click="
+                goPortrayal(
+                  'entDesc',
+                  article.winnerInfo[0].winnerId,
+                  'contact'
+                )
+              "
+              >获取更多</em
+            >
+          </span>
+          <span v-if="article.bidAmount">
+            <i class="l-d-item-label">中标金额:</i>
+            {{ moneyUnit(article.bidAmount) }}
+          </span>
+        </p>
+        <p
+          class="l-d-item"
+          v-if="
+            article.signendTime ||
+            article.bidendTime ||
+            article.bidEndTime ||
+            article.bidOpenTime
+          "
+        >
+          <span v-if="article.signendTime">
+            <i class="l-d-item-label">报名截止日期:</i>
+            {{ dateFromNow(article.signendTime * 1000) }}
+          </span>
+          <span v-if="article.bidendTime || article.bidEndTime">
+            <i class="l-d-item-label">投标截止日期:</i>
+            {{
+              dateFromNow(article.bidendTime * 1000) ||
+              dateFromNow(article.bidEndTime * 1000)
+            }}
+          </span>
+          <span v-if="article.bidOpenTime">
+            <i class="l-d-item-label">开标日期:</i>
+            {{ dateFromNow(article.bidOpenTime * 1000) }}
+          </span>
+        </p>
+      </div>
+    </div>
+    <div class="list-item-right">
+      <slot name="suffix"></slot>
     </div>
   </div>
 </template>
@@ -346,6 +383,10 @@ export default {
     tagClickList: {
       type: Array,
       default: () => []
+    },
+    forceShowDetail: {
+      type: Boolean,
+      default: false
     }
   },
   computed: {
@@ -365,14 +406,20 @@ export default {
     calcBudget() {
       // 先展示中标金额
       if (this.article.bidAmount) {
-        if(isNaN(this.article.bidAmount) && this.article.bidAmount.indexOf('登录') > -1) {
+        if (
+          isNaN(this.article.bidAmount) &&
+          this.article.bidAmount.indexOf('登录') > -1
+        ) {
           return this.article.bidAmount
         } else {
           return moneyUnit(this.article.bidAmount)
         }
       } else if (this.article.budget) {
         // 无中标金额展示预算金额
-        if(isNaN(this.article.budget) && this.article.budget.indexOf('登录') > -1) {
+        if (
+          isNaN(this.article.budget) &&
+          this.article.budget.indexOf('登录') > -1
+        ) {
           return this.article.budget
         } else {
           return moneyUnit(this.article.budget)
@@ -400,7 +447,7 @@ export default {
     calcDetail() {
       const extractDetail = extractKeywords(
         this.article.detail,
-        this.getMatchKeys,
+        this.getMatchKeys
       )
       if (extractDetail) {
         return replaceKeyword(extractDetail, this.getMatchKeys, [
@@ -421,7 +468,10 @@ export default {
       if (inFile) {
         const keyword = keywords[0]
         if (keyword?.length > 3) {
-          return `(<span class="highlight-text">${keyword.substring(0, 3)}</span>...在附件中)`
+          return `(<span class="highlight-text">${keyword.substring(
+            0,
+            3
+          )}</span>...在附件中)`
         } else {
           return `(<span class="highlight-text">${keyword}</span>在附件中)`
         }
@@ -442,6 +492,9 @@ export default {
     },
     // 处理关键词在附件中
     showDetailModel() {
+      if (this.forceShowDetail) {
+        return true
+      }
       const isOldVip = this.isVipBefore
       const isMember = this.bigmember
       const entNiche = this.entniche
@@ -456,20 +509,22 @@ export default {
       }
     },
     // 处理采购单位类型是否展示
-    calcBuyerclass () {
+    calcBuyerclass() {
       const buyerClass = this.article.buyerclass || this.article.buyerClass
-      return buyerClass && buyerClass !== '其它' && buyerClass.indexOf("登录")<0
+      return (
+        buyerClass && buyerClass !== '其它' && buyerClass.indexOf('登录') < 0
+      )
     },
     calcArea() {
       const v = this.article
       const region = []
-      if(v.area && (v.city && v.city.indexOf(v.area) === -1)) {
+      if (v.area && v.city && v.city.indexOf(v.area) === -1) {
         region.push(v.area)
       }
-      if(v.city) {
+      if (v.city) {
         region.push(v.city)
       }
-      if(v.district) {
+      if (v.district) {
         region.push(v.district)
       }
       v.region = region.join('-')
@@ -519,7 +574,7 @@ export default {
       })
     },
     // 参标
-    joinBidChange () {
+    joinBidChange() {
       this.$emit('onJoinBid', this.article)
     },
     setShow() {
@@ -537,8 +592,8 @@ export default {
       return arr
     },
     // 标签点击事件
-    tagClick (label) {
-      if(this.tagClickList?.includes(label)) {
+    tagClick(label) {
+      if (this.tagClickList?.includes(label)) {
         this.$emit('tag-click', label)
       }
     }
@@ -600,11 +655,15 @@ export default {
 $border-color: #ececec;
 @include diy-icon('time', 20, 20);
 .article-item {
-  // display: flex;
-  // align-items: center;
-  // justify-content: space-between;
-  padding: 16px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
   border-bottom: 1px solid $border-color;
+  .list-item-content {
+    flex: 1;
+    padding: 16px;
+    max-width: 100%;
+  }
 
   &:first-of-type,
   &:border-top {
@@ -722,6 +781,7 @@ $border-color: #ececec;
   }
   .a-i-detail {
     width: calc(100% - 84px);
+    max-width: 920px;
     padding: 6px 40px 0 30px;
     font-size: 14px;
     line-height: 22px;
@@ -794,18 +854,18 @@ $border-color: #ececec;
       align-items: unset;
     }
   }
-  &.style-for-bidding{
+  &.style-for-bidding {
     .a-i-right {
-      padding-left:0;
+      padding-left: 0;
     }
     .tag-handle {
       cursor: pointer;
-      &:hover{
+      &:hover {
         text-decoration: underline;
       }
     }
-    .list-detail{
-      padding-left:0;
+    .list-detail {
+      padding-left: 0;
     }
   }
 }

+ 8 - 0
apps/bigmember_pc/src/router/modules/relationship.js

@@ -0,0 +1,8 @@
+export default [
+  // 标讯搜索
+  {
+    path: '/relationship/find',
+    name: 'relationshipFind',
+    component: () => import('@/views/relationship/find.vue')
+  }
+]

+ 25 - 15
apps/bigmember_pc/src/router/router-interceptors.js

@@ -10,7 +10,8 @@ const powerCheckPathWhiteRegList = [
   /\/big\/page\/index/,
   /medical/,
   /set-/,
-  new RegExp('(^/dw)|(^/qy)'), // seo画像路由
+  /relationship/,
+  /^(\/dw)|(\/qy)/, // seo画像路由
   /filepack/,
   /order/,
   /article/,
@@ -56,7 +57,8 @@ const powerCheckWhiteList = [
 ]
 
 const regListCheck = function (regList, path) {
-  if (!Array.isArray(regList)) return false
+  if (!Array.isArray(regList))
+    return false
   return regList.some((reg) => {
     return reg.test(path)
   })
@@ -77,20 +79,21 @@ router.beforeEach(async (to, from, next) => {
     // 调用商机管理权限接口 查用户有无画像分析系统权限 有则执行下一步 无则返回首页
     if (entNiche.privatedata) {
       next()
-    } else {
+    }
+    else {
       location.href = location.origin
     }
     return
   }
   if (
-    powerCheckWhiteList.includes(to.name) ||
-    regListCheck(powerCheckPathWhiteRegList, to.path)
+    powerCheckWhiteList.includes(to.name)
+    || regListCheck(powerCheckPathWhiteRegList, to.path)
   ) {
     // 权限列表:https://app-jytest.jydev.jianyu360.com/jyapp/big-member/js/main_root_data.js
     // 4.企业全景分析
     // 13.企业中标动态
-    const hasEntPortPower =
-      info.memberStatus > 0 && (power.includes(4) || power.includes(13))
+    const hasEntPortPower
+      = info.memberStatus > 0 && (power.includes(4) || power.includes(13))
     if (hasEntPortPower) {
       // 大会员有画像权限用户,访问超级订阅画像,则重定向到大会员画像
       if (to.name === 'ent_ser_portrait') {
@@ -103,10 +106,12 @@ router.beforeEach(async (to, from, next) => {
             resource: to.query.resource
           }
         })
-      } else {
+      }
+      else {
         next()
       }
-    } else {
+    }
+    else {
       if (to.name === 'ent_portrait') {
         // 其他无画像权限用户,访问大会员画像,则重定向到超级订阅画像
         next({
@@ -116,20 +121,24 @@ router.beforeEach(async (to, from, next) => {
             ...to.query
           }
         })
-      } else {
+      }
+      else {
         next()
       }
     }
-  } else {
+  }
+  else {
     let href = '/big/page/index'
     const { pass, anchor } = powerCheck(info, power, to, from)
     if (pass) {
       next()
-    } else {
+    }
+    else {
       // TODO 可优化 临时判断是否旧项目大会员支付路由,skip
       if (to.fullPath.startsWith('/front/member/memberDetail')) {
         // skip
-      } else {
+      }
+      else {
         if (anchor) {
           href = `${href}#${anchor}`
         }
@@ -143,11 +152,12 @@ router.beforeEach(async (to, from, next) => {
  * 非工作桌面环境下,修改页面 title
  */
 router.beforeEach((to, from, next) => {
-  if (location.href.indexOf('page_workDesktop') === -1) {
+  if (!location.href.includes('page_workDesktop')) {
     // 标题设置
     if (to?.meta?.title) {
       document.title = to.meta.title
-    } else {
+    }
+    else {
       document.title = '剑鱼标讯'
     }
   }

+ 10 - 5
apps/bigmember_pc/src/router/router.js

@@ -10,6 +10,7 @@ import analyse from './modules/analyse'
 import search from './modules/search'
 import bidding from './modules/bidding'
 import report from './modules/report'
+import relationship from './modules/relationship'
 
 if (import.meta.env.NODE_ENV !== 'production') {
   Vue.use(VueRouter)
@@ -31,6 +32,7 @@ const router = new VueRouter({
     ...search,
     ...bidding,
     ...report,
+    ...relationship,
     {
       path: '/404',
       name: '404',
@@ -38,7 +40,7 @@ const router = new VueRouter({
     }
   ],
   // https://v3.router.vuejs.org/zh/guide/advanced/scroll-behavior.html#%E5%BC%82%E6%AD%A5%E6%BB%9A%E5%8A%A8
-  scrollBehavior(to, from, savedPosition) {
+  scrollBehavior(to) {
     // 模拟“滚动到锚点”的行为
     if (to.hash) {
       if (to.hash.includes('$') || to.hash.startsWith('#.')) {
@@ -55,19 +57,22 @@ const router = new VueRouter({
                 .querySelector(selector)
                 .scrollIntoView({ behavior: 'smooth', block: 'center' })
             }, delay)
-          } catch (error) {
+          }
+          catch (error) {
             console.error(error)
           }
         }
         return {
           selector
         }
-      } else {
+      }
+      else {
         return {
           selector: to.hash
         }
       }
-    } else {
+    }
+    else {
       return { x: 0, y: 0 }
     }
   }
@@ -75,7 +80,7 @@ const router = new VueRouter({
 
 const originalPush = VueRouter.prototype.push
 VueRouter.prototype.push = function push(location) {
-  return originalPush.call(this, location).catch((err) => err)
+  return originalPush.call(this, location).catch(err => err)
 }
 
 export default router

+ 250 - 0
apps/bigmember_pc/src/views/relationship/components/CollectionRelationList.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="relationship-list-container">
+    <div class="relationship-main" v-loading="listState.loading">
+      <div class="relationship-list">
+        <article-item
+          class="list-item"
+          v-for="(item, index) in listState.list"
+          :class="{ visited: item.visited || item.ca_isvisit }"
+          :key="index"
+          :index="index + 1"
+          :article="item"
+          :config="config"
+          :vt="autoVt"
+          @onClick="toDetail(item)"
+        >
+          <template #right-time>
+            <span>{{ dateFromNow(item.publishTime * 1000) }}</span>
+          </template>
+          <template #right-handle-container>
+            <el-button
+              class="find-button"
+              type="primary"
+              plain
+              @click="toFindRel(item)"
+              >找人脉</el-button
+            >
+          </template>
+        </article-item>
+        <Empty v-if="listState.list.length === 0 && listState.loaded">
+          <!-- 有收藏,无匹配 -->
+          <p v-if="jiankongInfo.has">当前收藏项目无需找人脉项目</p>
+          <!-- 无收藏,无匹配 -->
+          <p v-else>
+            您尚未收藏任何项目,<span
+              class="highlight-text pointer"
+              @click="toCollection"
+              >去收藏</span
+            >。
+          </p>
+        </Empty>
+      </div>
+    </div>
+    <div class="relationship-footer">
+      <div class="pagination-container">
+        <span
+          class="pagination-wrapper"
+          v-if="listState.total > listState.pageSize"
+        >
+          <el-pagination
+            popper-class="pagination-custom-select"
+            background
+            :page-size="listState.pageSize"
+            :page-sizes="[5, 10, 50, 100]"
+            :current-page="listState.pageNum"
+            @size-change="onSizeChange"
+            @current-change="onPageChange"
+            layout="prev, pager, next, sizes, jumper"
+            :total="listState.total"
+            :show-confirm-btn="true"
+          >
+          </el-pagination>
+          <p class="pagination-tip">
+            为您展示前5000条,可细化筛选条件查看更多信息
+          </p>
+        </span>
+      </div>
+    </div>
+    <FindRelDrawer :id="drawer.id" :visible.sync="drawer.show" />
+  </div>
+</template>
+
+<script>
+import { Pagination, Button } from 'element-ui'
+import { mapGetters } from 'vuex'
+import ArticleItem from '@/components/article-item/ArticleItem.vue'
+import FindRelDrawer from './FindRelDrawer'
+import Empty from '@/components/common/Empty'
+import { getNetworkManageCollectionList } from '@/api/modules/bi'
+import { dateFromNow, openLinkInWorkspace } from '@/utils/'
+export default {
+  name: 'MonitorRelationList',
+  components: {
+    [Pagination.name]: Pagination,
+    [Button.name]: Button,
+    FindRelDrawer,
+    ArticleItem,
+    Empty
+  },
+  data() {
+    return {
+      drawer: {
+        id: '',
+        show: false
+      },
+      jiankongInfo: {
+        has: false
+      },
+      listState: {
+        loading: false,
+        loaded: false,
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+        list: [
+          // {
+          //   "id": "ABCY1xFcD0eIy04NGN3cHJaJCcvESR0ZlVgKw43Ky4NZGpzdD9UCf0%3D",
+          //   "area": "江苏",
+          //   "areaUrl": "/list/city/JS_SZ_SZGYYQ.html",
+          //   "buyerClass": "信息技术",
+          //   "city": "苏州市",
+          //   "detail": "综合运用大数据、物联网、云计算、人工智能等新技术,逐步构建全面感知、动态监测、智能预警、扁平指挥、快速处置、精准监管的应急管理信息化新格局,以数据驱动、技术赋能和技术替代为理念,主动适应“新风险、新体制、新机制、新技术”要求,满足“",
+          //   "industry": "信息技术",
+          //   "publishTime": 1684252800,
+          //   "subtype": "竞谈",
+          //   "subtypeUrl": "/list/stype/ZBGG_JT.html",
+          //   "title": "苏州新建元数字科技有限公司关于可视化综合指挥调度子系统模块研发服务项目竞争性磋商采购公告",
+          //   "budget": 588000,
+          //   "buyer": "苏州新建元数字科技有限公司",
+          //   "buyerTel": "0512-66600126",
+          //   "buyerPerson": "钱臻轶",
+          //   "agency": "苏州市创杰招投标咨询服务有限公司",
+          //   "agencyTel": "0512-65238816",
+          //   "bidOpenTime": 1685064600,
+          //   "bidEndTime": 1685064600,
+          //   "site": "元博网(采购与招标网)",
+          //   "spiderCode": "a_ybwcgyzbw_zfcg",
+          //   "projectInfo": {},
+          //   "district": "苏州工业园区",
+          // },
+        ]
+      },
+      config: {
+        gray: true,
+        table: false,
+        collect: false
+      }
+    }
+  },
+  computed: {
+    ...mapGetters('user', {
+      autoVt: 'vt'
+    })
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    dateFromNow,
+    // 获取列表数据
+    async getList() {
+      const params = {
+        pageNum: this.listState.pageNum,
+        pageSize: this.listState.pageSize
+      }
+      if (this.listState.loading) {
+        return
+      }
+      this.listState.loading = true
+      try {
+        const { data, error_code: code } =
+          await getNetworkManageCollectionList(params)
+        if (code === 0 && data) {
+          // this.jiankongInfo.has = data.hasCollect
+          // this.listState.list = data.list || []
+          // this.listState.total = data.total || 0
+
+          this.jiankongInfo.has = false
+          this.listState.list = []
+          this.listState.total = 0
+        }
+      } catch (error) {
+        console.log(error)
+      } finally {
+        this.listState.loaded = true
+        this.listState.loading = false
+      }
+    },
+    toFindRel(item) {
+      const { _id } = item
+      this.drawer.id = _id
+      this.drawer.show = true
+    },
+    async toDetail(item) {
+      const { _id } = item
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem('/article/content/*.html', `id=${_id}`)
+      )
+      // 在工作桌面内打开三级页
+      openLinkInWorkspace(true, {
+        url: `/article/content/${_id}.html`,
+        newTab: true
+      })
+    },
+    toCollection() {
+      openLinkInWorkspace(true, {
+        url: '/swordfish/frontPage/collection/sess/index',
+        newTab: true
+      })
+    },
+    onSizeChange(val) {
+      this.listState.pageSize = val
+      this.listState.pageNum = 1
+      this.getList()
+    },
+    onPageChange(val) {
+      this.listState.pageNum = val
+      this.getList()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.relationship-list-container {
+  box-sizing: border-box;
+  min-height: 200px;
+  ::v-deep {
+    .a-i-right {
+      padding: 8px 0 0 0px;
+    }
+    .list-detail {
+      padding: 0;
+    }
+  }
+  .list-item:hover {
+    background: #f7f9fc;
+  }
+  .relationship-main {
+    min-height: 200px;
+  }
+  .pagination-wrapper {
+    padding: 0 16px;
+    font-size: 14px;
+    line-height: 22px;
+    color: #686868;
+    text-align: right;
+  }
+  .pagination-container {
+    padding-right: 16px;
+  }
+  .pagination-tip {
+    margin-top: 16px;
+  }
+}
+.find-button {
+  padding: 6px 16px;
+  border: 1px solid;
+  background: transparent;
+}
+</style>

+ 60 - 0
apps/bigmember_pc/src/views/relationship/components/FindRelDrawer.vue

@@ -0,0 +1,60 @@
+<template>
+  <el-drawer
+    title="推荐人脉列表"
+    :visible="visible"
+    @update:visible="onUpdateVisible"
+    size="70%"
+    direction="rtl"
+  >
+    <div class="drawer-content">
+      <iframe :src="src" frameborder="0"></iframe>
+    </div>
+  </el-drawer>
+</template>
+
+<script>
+import { Drawer } from 'element-ui'
+export default {
+  name: 'RelDrawer',
+  components: {
+    [Drawer.name]: Drawer
+  },
+  props: {
+    visible: {
+      type: Boolean,
+      default: false
+    },
+    id: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    return {
+      baseUrl:
+        '/succbi/rmt/app/rmt.app/connection/connection_project_relation.spg'
+    }
+  },
+  computed: {
+    src() {
+      return `${this.baseUrl}?E_W_ID=${this.id}`
+    }
+  },
+  methods: {
+    onUpdateVisible(e) {
+      this.$emit('update:visible', e)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.drawer-content {
+  width: 100%;
+  height: 100%;
+  iframe {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 248 - 0
apps/bigmember_pc/src/views/relationship/components/MonitorRelationList.vue

@@ -0,0 +1,248 @@
+<template>
+  <div class="relationship-list-container">
+    <div class="relationship-main" v-loading="listState.loading">
+      <div class="relationship-list">
+        <article-item
+          class="list-item"
+          model="D"
+          v-for="(item, index) in listState.list"
+          :class="{ visited: item.visited || item.ca_isvisit }"
+          :key="index"
+          :index="index + 1"
+          :article="item"
+          :config="config"
+          :vt="autoVt"
+          forceShowDetail
+          @onClick="toDetail(item)"
+        >
+          <template #right-time>
+            <span>{{ dateFromNow(item.publishTime * 1000) }}</span>
+          </template>
+          <template #right-handle-container>
+            <el-button
+              class="find-button"
+              type="primary"
+              plain
+              @click="toFindRel(item)"
+              >找人脉</el-button
+            >
+          </template>
+        </article-item>
+        <Empty v-if="listState.list.length === 0 && listState.loaded">
+          <!-- 已监控,无匹配 -->
+          <p v-if="jiankongInfo.has">当前监控业主无需找人脉项目</p>
+          <!-- 无监控,无匹配 -->
+          <p v-else>
+            当前监控业主无需找人脉项目,<span
+              class="highlight-text pointer"
+              @click="toJiankong"
+              >去监控</span
+            >。
+          </p>
+        </Empty>
+      </div>
+    </div>
+    <div class="relationship-footer">
+      <div class="pagination-container">
+        <span
+          class="pagination-wrapper"
+          v-if="listState.total > listState.pageSize"
+        >
+          <el-pagination
+            popper-class="pagination-custom-select"
+            background
+            :page-size="listState.pageSize"
+            :page-sizes="[5, 10, 50, 100]"
+            :current-page="listState.pageNum"
+            @size-change="onSizeChange"
+            @current-change="onPageChange"
+            layout="prev, pager, next, sizes, jumper"
+            :total="listState.total"
+            :show-confirm-btn="true"
+          >
+          </el-pagination>
+          <p class="pagination-tip">
+            为您展示前5000条,可细化筛选条件查看更多信息
+          </p>
+        </span>
+      </div>
+    </div>
+    <FindRelDrawer :id="drawer.id" :visible.sync="drawer.show" />
+  </div>
+</template>
+
+<script>
+import { Pagination, Button } from 'element-ui'
+import { mapGetters } from 'vuex'
+import ArticleItem from '@/components/article-item/ArticleItem.vue'
+import FindRelDrawer from './FindRelDrawer'
+import Empty from '@/components/common/Empty'
+import { getNetworkManageMonitorList } from '@/api/modules/bi'
+import { dateFromNow, openLinkInWorkspace } from '@/utils/'
+export default {
+  name: 'MonitorRelationList',
+  components: {
+    [Pagination.name]: Pagination,
+    [Button.name]: Button,
+    Empty,
+    FindRelDrawer,
+    ArticleItem
+  },
+  data() {
+    return {
+      drawer: {
+        id: '',
+        show: false
+      },
+      jiankongInfo: {
+        has: false
+      },
+      listState: {
+        loading: false,
+        loaded: false,
+        pageNum: 1,
+        pageSize: 10,
+        total: 0,
+        list: [
+          // {
+          //   "id": "ABCY1xFcD0eIy04NGN3cHJaJCcvESR0ZlVgKw43Ky4NZGpzdD9UCf0%3D",
+          //   "area": "江苏",
+          //   "areaUrl": "/list/city/JS_SZ_SZGYYQ.html",
+          //   "buyerClass": "信息技术",
+          //   "city": "苏州市",
+          //   "detail": "综合运用大数据、物联网、云计算、人工智能等新技术,逐步构建全面感知、动态监测、智能预警、扁平指挥、快速处置、精准监管的应急管理信息化新格局,以数据驱动、技术赋能和技术替代为理念,主动适应“新风险、新体制、新机制、新技术”要求,满足“",
+          //   "industry": "信息技术",
+          //   "publishTime": 1684252800,
+          //   "subtype": "竞谈",
+          //   "subtypeUrl": "/list/stype/ZBGG_JT.html",
+          //   "title": "苏州新建元数字科技有限公司关于可视化综合指挥调度子系统模块研发服务项目竞争性磋商采购公告",
+          //   "budget": 588000,
+          //   "buyer": "苏州新建元数字科技有限公司",
+          //   "buyerTel": "0512-66600126",
+          //   "buyerPerson": "钱臻轶",
+          //   "agency": "苏州市创杰招投标咨询服务有限公司",
+          //   "agencyTel": "0512-65238816",
+          //   "bidOpenTime": 1685064600,
+          //   "bidEndTime": 1685064600,
+          //   "site": "元博网(采购与招标网)",
+          //   "spiderCode": "a_ybwcgyzbw_zfcg",
+          //   "projectInfo": {},
+          //   "district": "苏州工业园区",
+          // },
+        ]
+      },
+      config: {
+        gray: true,
+        table: false,
+        collect: false
+      }
+    }
+  },
+  computed: {
+    ...mapGetters('user', {
+      autoVt: 'vt'
+    })
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    dateFromNow,
+    // 获取列表数据
+    async getList() {
+      const params = {
+        pageNum: this.listState.pageNum,
+        pageSize: this.listState.pageSize
+      }
+      if (this.listState.loading) {
+        return
+      }
+      this.listState.loading = true
+      try {
+        const { data, error_code: code } =
+          await getNetworkManageMonitorList(params)
+        if (code === 0 && data) {
+          this.jiankongInfo.has = data.hasMonitor
+          this.listState.list = data.list || []
+          this.listState.total = data.total || 0
+        }
+      } catch (error) {
+        console.log(error)
+      } finally {
+        this.listState.loaded = true
+        this.listState.loading = false
+      }
+    },
+    toFindRel(item) {
+      const { _id } = item
+      this.drawer.id = _id
+      this.drawer.show = true
+    },
+    async toDetail(item) {
+      const { _id } = item
+      item.visited = true
+      this.pathVisiting(
+        this.createPathItem('/article/content/*.html', `id=${_id}`)
+      )
+      // 在工作桌面内打开三级页
+      openLinkInWorkspace(true, {
+        url: `/article/content/${_id}.html`,
+        newTab: true
+      })
+    },
+    toJiankong() {
+      openLinkInWorkspace(true, {
+        url: '/jylab/purSearch/index.html',
+        newTab: true
+      })
+    },
+    onSizeChange(val) {
+      this.listState.pageSize = val
+      this.listState.pageNum = 1
+      this.getList()
+    },
+    onPageChange(val) {
+      this.listState.pageNum = val
+      this.getList()
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.relationship-list-container {
+  box-sizing: border-box;
+  ::v-deep {
+    .a-i-right {
+      padding: 8px 0 0 0px;
+    }
+    .list-detail {
+      padding: 0;
+    }
+  }
+  .list-item:hover {
+    background: #f7f9fc;
+  }
+
+  .relationship-main {
+    min-height: 200px;
+  }
+  .pagination-wrapper {
+    padding: 0 16px;
+    font-size: 14px;
+    line-height: 22px;
+    color: #686868;
+    text-align: right;
+  }
+  .pagination-container {
+    padding-right: 16px;
+  }
+  .pagination-tip {
+    margin-top: 16px;
+  }
+}
+.find-button {
+  padding: 6px 16px;
+  border: 1px solid;
+  background: transparent;
+}
+</style>

+ 70 - 0
apps/bigmember_pc/src/views/relationship/find.vue

@@ -0,0 +1,70 @@
+<template>
+  <div class="relationship-find-container">
+    <el-tabs v-model="activeName">
+      <el-tab-pane label="找人脉" name="first" disabled></el-tab-pane>
+      <el-tab-pane label="业主监控项目找人脉" name="second" lazy>
+        <MonitorRelationList />
+      </el-tab-pane>
+      <el-tab-pane label="标讯收藏项目找人脉" name="third" lazy>
+        <CollectionRelationList />
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import { Tabs, TabPane } from 'element-ui'
+import MonitorRelationList from './components/MonitorRelationList'
+import CollectionRelationList from './components/CollectionRelationList'
+export default {
+  name: 'RelationshipList',
+  components: {
+    [Tabs.name]: Tabs,
+    [TabPane.name]: TabPane,
+    MonitorRelationList,
+    CollectionRelationList
+  },
+  data() {
+    return {
+      activeName: 'second'
+    }
+  },
+  methods: {}
+}
+</script>
+<style lang="scss" scoped>
+::v-deep {
+  #tab-first,
+  .el-tabs__item {
+    color: #686868;
+    &.is-active {
+      color: $color_main;
+    }
+  }
+  .el-tabs__item:hover {
+    color: $color_main;
+  }
+}
+
+.relationship-find-container {
+  padding: 24px;
+  .el-tabs {
+    background-color: #fff;
+    border-radius: 8px;
+    ::v-deep {
+      .el-tabs__header {
+        margin-bottom: 0;
+      }
+      .el-tabs__nav-scroll {
+        padding: 0 32px;
+      }
+      .el-tabs__nav {
+        padding: 4px 0;
+      }
+      .el-tabs__item {
+        font-size: 16px;
+      }
+    }
+  }
+}
+</style>

+ 7 - 6
configs/proxy/dev-proxy.js

@@ -8,7 +8,6 @@ const ProxyTargets = {
   app5: 'https://app5-jytest.jydev.jianyu360.com'
 }
 
-
 // 需要代理的请求前缀
 const ProxyPrefixes = [
   // 请求代理
@@ -44,21 +43,23 @@ const ProxyPrefixes = [
   '/images/wx/'
 ]
 
-
-export function useServerProxy (domain, defaultProxy = {}) {
+export function useServerProxy(domain, defaultProxy = {}) {
   const ProxyTarget = ProxyTargets[domain] || domain
   const DevProxy = Object.assign({}, defaultProxy, {
     '^/dev-api': {
       target: ProxyTarget,
       changeOrigin: true,
-      rewrite: (path) =>
-        path.replace(/^\/dev-api/, '/')
+      rewrite: (path) => path.replace(/^\/dev-api/, '/')
+    },
+    '^/succbi': {
+      target: ProxyTarget,
+      changeOrigin: true
     },
     // 接口解密iframe
     '^/page_decrypt': {
       target: ProxyTarget,
       changeOrigin: true
-    },
+    }
   })
   const ProxyRules = ProxyPrefixes.reduce((a, b) => {
     a[b] = ProxyTarget