lianbingjie 1 anno fa
parent
commit
856a5f23cd
69 ha cambiato i file con 2547 aggiunte e 190 eliminazioni
  1. 31 30
      apps/bigmember_pc/.eslintrc.cjs
  2. 1 0
      apps/bigmember_pc/config/proxy.js
  3. 21 0
      apps/bigmember_pc/src/api/modules/business.js
  4. 2 0
      apps/bigmember_pc/src/api/modules/index.js
  5. 11 0
      apps/bigmember_pc/src/api/modules/message.js
  6. 8 0
      apps/bigmember_pc/src/api/modules/pay.js
  7. 37 0
      apps/bigmember_pc/src/api/modules/workspace.js
  8. BIN
      apps/bigmember_pc/src/assets/images/business/tip-bg.png
  9. BIN
      apps/bigmember_pc/src/assets/images/icon/fireworks.png
  10. BIN
      apps/bigmember_pc/src/assets/images/icon/icon_right2.png
  11. BIN
      apps/bigmember_pc/src/assets/images/workspace/db.png
  12. BIN
      apps/bigmember_pc/src/assets/images/workspace/my-claim.png
  13. BIN
      apps/bigmember_pc/src/assets/images/workspace/my-collect.png
  14. BIN
      apps/bigmember_pc/src/assets/images/workspace/my-customer.png
  15. BIN
      apps/bigmember_pc/src/assets/images/workspace/my-gen.png
  16. BIN
      apps/bigmember_pc/src/assets/images/workspace/my-project.png
  17. BIN
      apps/bigmember_pc/src/assets/images/workspace/qb.png
  18. 5 0
      apps/bigmember_pc/src/components/collect-info/CollectInfo.vue
  19. 2 1
      apps/bigmember_pc/src/components/common/ContentLayout.vue
  20. 3 4
      apps/bigmember_pc/src/components/forecast/ForeCast.vue
  21. 1 1
      apps/bigmember_pc/src/components/push-list/PotentialList.vue
  22. 2 1
      apps/bigmember_pc/src/router/router-interceptors.js
  23. 8 0
      apps/bigmember_pc/src/router/routers.js
  24. 18 1
      apps/bigmember_pc/src/store/workspace.js
  25. 0 0
      apps/bigmember_pc/src/store/workspace/account-info.js
  26. 123 0
      apps/bigmember_pc/src/store/workspace/business-todo.js
  27. 6 2
      apps/bigmember_pc/src/store/workspace/common-use.js
  28. 60 0
      apps/bigmember_pc/src/store/workspace/important-news.js
  29. 60 0
      apps/bigmember_pc/src/store/workspace/industry-report.js
  30. 2 1
      apps/bigmember_pc/src/store/workspace/message.js
  31. 32 20
      apps/bigmember_pc/src/store/workspace/my-customer.js
  32. 2 2
      apps/bigmember_pc/src/store/workspace/subscribe.js
  33. 374 0
      apps/bigmember_pc/src/views/business/detail.vue
  34. 87 0
      apps/bigmember_pc/src/views/workspace/components/AccountInfo.vue
  35. 46 0
      apps/bigmember_pc/src/views/workspace/components/AnalysisReport.vue
  36. 193 0
      apps/bigmember_pc/src/views/workspace/components/BusinessToDo.vue
  37. 97 0
      apps/bigmember_pc/src/views/workspace/components/ChatList.vue
  38. 35 10
      apps/bigmember_pc/src/views/workspace/components/CommonUse.vue
  39. 3 0
      apps/bigmember_pc/src/views/workspace/components/MessageTips.vue
  40. 222 0
      apps/bigmember_pc/src/views/workspace/components/MyEquityList.vue
  41. 50 0
      apps/bigmember_pc/src/views/workspace/components/NewsList.vue
  42. 2 2
      apps/bigmember_pc/src/views/workspace/components/SubscribeList.vue
  43. 44 26
      apps/bigmember_pc/src/views/workspace/dashboard.vue
  44. 4 2
      apps/bigmember_pc/src/views/workspace/ui/ArticleItem.vue
  45. 139 0
      apps/bigmember_pc/src/views/workspace/ui/ChatItem.vue
  46. 112 0
      apps/bigmember_pc/src/views/workspace/ui/EquityItem.vue
  47. 6 4
      apps/bigmember_pc/src/views/workspace/ui/ListCard.vue
  48. 1 1
      apps/bigmember_pc/src/views/workspace/ui/WorkspaceCard.vue
  49. 14 0
      apps/mobile/src/api/modules/bigmember.js
  50. 19 0
      apps/mobile/src/api/modules/business.js
  51. 1 0
      apps/mobile/src/api/modules/index.js
  52. BIN
      apps/mobile/src/assets/image/business/tip-bg.png
  53. BIN
      apps/mobile/src/assets/image/icon/icon-phone.png
  54. BIN
      apps/mobile/src/assets/image/icon/icon-right2.png
  55. 7 1
      apps/mobile/src/components/treasure-box/AllUse.vue
  56. 64 0
      apps/mobile/src/components/treasure-box/CommonUse.vue
  57. 12 0
      apps/mobile/src/router/modules/business.js
  58. 13 1
      apps/mobile/src/store/modules/treasureBox.js
  59. 310 0
      apps/mobile/src/views/business/Detail.vue
  60. 1 1
      apps/mobile/src/views/tabbar/Box.vue
  61. 25 2
      apps/mobile/src/views/treasurebox/FeatureSettings.vue
  62. 50 3
      apps/mobile/src/views/uersales/newuser/index.vue
  63. 1 0
      apps/work-bench/.env.development
  64. 1 0
      apps/work-bench/.env.production
  65. 2 2
      apps/work-bench/public/index.html
  66. 1 1
      apps/work-bench/src/components/NavUserInfo.vue
  67. 1 1
      apps/work-bench/src/register-app.js
  68. 1 1
      packages/work-bench-frame/packages/components/Navbar/components/item.vue
  69. 174 69
      packages/work-bench-frame/packages/components/Navbar/index.vue

+ 31 - 30
apps/bigmember_pc/.eslintrc.cjs

@@ -1,30 +1,31 @@
-/* eslint-env node */
-require('@rushstack/eslint-patch/modern-module-resolution')
-module.exports = {
-  root: true,
-  env: {
-    browser: true,
-    node: true
-  },
-  globals: {
-    loginflag: true,
-    $: true,
-    JyObj: true,
-    _hmt: true,
-    vComponentChart: true
-  },
-  plugins: ['vue'],
-  rules: {
-    'vue/no-mutating-props': 'off',
-    'vue/multi-word-component-names': 'off',
-    'no-empty': ['error', { allowEmptyCatch: true }],
-    'no-unused-vars': 'off',
-    'no-console': 'off',
-    'no-debugger': 'warn'
-  },
-  extends: [
-    'plugin:vue/essential',
-    'eslint:recommended',
-    '@vue/eslint-config-prettier'
-  ]
-}
+/* eslint-env node */
+require('@rushstack/eslint-patch/modern-module-resolution')
+module.exports = {
+  root: true,
+  env: {
+    browser: true,
+    node: true
+  },
+  globals: {
+    loginflag: true,
+    $: true,
+    JyObj: true,
+    _hmt: true,
+    vComponentChart: true
+  },
+  plugins: ['vue'],
+  rules: {
+    'vue/no-mutating-props': 'off',
+    'vue/multi-word-component-names': 'off',
+    'no-empty': ['error', { allowEmptyCatch: true }],
+    'no-unused-vars': 'off',
+    'no-console': 'off',
+    'no-debugger': 'warn',
+    'no-useless-escape': 'off'
+  },
+  extends: [
+    'plugin:vue/essential',
+    'eslint:recommended',
+    '@vue/eslint-config-prettier'
+  ]
+}

+ 1 - 0
apps/bigmember_pc/config/proxy.js

@@ -16,6 +16,7 @@ const PrefixAPIS = [
   '/userCenter',
   '/jyMerge',
   '/jyapi',
+  '/message',
   // 资源
   '/commonFunctions',
   '/common-module',

+ 21 - 0
apps/bigmember_pc/src/api/modules/business.js

@@ -0,0 +1,21 @@
+import request from '@/api'
+import qs from 'qs'
+
+export function getBusinessDetails(data) {
+  data = qs.stringify(data)
+  return request({
+    baseURL: '/bigmember',
+    url: '/project/businessDetails',
+    method: 'POST',
+    data
+  })
+}
+
+// 是否需要完善信息提示
+export function isNeedCompleteInfo() {
+  return request({
+    baseURL: '/salesLeads',
+    url: '/businessRetain',
+    method: 'POST'
+  })
+}

+ 2 - 0
apps/bigmember_pc/src/api/modules/index.js

@@ -27,3 +27,5 @@ export * from './course'
 export * from './jyMerge'
 export * from './crmApplication'
 export * from './pay'
+export * from './message'
+export * from './business'

+ 11 - 0
apps/bigmember_pc/src/api/modules/message.js

@@ -0,0 +1,11 @@
+import request from '@/api'
+
+// 获取聊天会话列表
+export function getUserSessionList(data) {
+  return request({
+    baseURL: '/jyapi',
+    url: '/message/userList',
+    method: 'post',
+    data
+  })
+}

+ 8 - 0
apps/bigmember_pc/src/api/modules/pay.js

@@ -48,3 +48,11 @@ export function filePackUseHistory(data) {
     data
   })
 }
+
+export function getUserAccountShow() {
+  return request({
+    baseURL: '/jypay',
+    url: '/user/account/show',
+    method: 'POST'
+  })
+}

+ 37 - 0
apps/bigmember_pc/src/api/modules/workspace.js

@@ -103,3 +103,40 @@ export function getWhatIsWorkspace() {
     method: 'get'
   })
 }
+
+// 工作台首页-要闻
+export function getWorkspaceNews() {
+  return request({
+    baseURL: '/front',
+    url: '/project/importantNews',
+    method: 'get'
+  })
+}
+
+// 工作台首页-行业分析简报
+export function getWorkspaceIndustryReport() {
+  return request({
+    baseURL: '/front',
+    url: '/project/deskAnalysisReport',
+    method: 'get'
+  })
+}
+
+// 工作台首页-我的企业关注、项目关注、标讯收藏、认领等权益数量(客户监控在另外接口返回)
+export function getWorkspaceEquityCount() {
+  return request({
+    baseURL: '/bigmember',
+    url: '/project/meMonitoring',
+    method: 'get'
+  })
+}
+
+// 工作台首页-商机情报、待办消息列表(getMessageCenterList接口简版)
+export function getBusinessTodoList(data) {
+  return request({
+    baseURL: '/jyapi/messageCenter',
+    url: '/WorkDeskList',
+    method: 'POST',
+    data
+  })
+}

BIN
apps/bigmember_pc/src/assets/images/business/tip-bg.png


BIN
apps/bigmember_pc/src/assets/images/icon/fireworks.png


BIN
apps/bigmember_pc/src/assets/images/icon/icon_right2.png


BIN
apps/bigmember_pc/src/assets/images/workspace/db.png


BIN
apps/bigmember_pc/src/assets/images/workspace/my-claim.png


BIN
apps/bigmember_pc/src/assets/images/workspace/my-collect.png


BIN
apps/bigmember_pc/src/assets/images/workspace/my-customer.png


BIN
apps/bigmember_pc/src/assets/images/workspace/my-gen.png


BIN
apps/bigmember_pc/src/assets/images/workspace/my-project.png


BIN
apps/bigmember_pc/src/assets/images/workspace/qb.png


+ 5 - 0
apps/bigmember_pc/src/components/collect-info/CollectInfo.vue

@@ -541,6 +541,7 @@ export default {
           '请升级大会员,可实时监控最多500个业主采购动态,洞察潜在商机。',
         pc_buyer_monitor_limit:
           '监控业主数量已达上限,请升级大会员,可实时监控最多500个业主采购动态,洞察潜在商机。',
+<<<<<<< HEAD
         peugeot_supplier_regist: '请完善您的个人信息,抢先对接采购单位。',
         pc_article_project_more: '请升级大会员,可实时监控最多500个项目动态,不错过任何一个重要商机。',
         pc_article_cqxmmore: '请升级大会员,提前1-3个月获取项目采购计划,获取采购内容,提前运作提高中标率。',
@@ -548,6 +549,10 @@ export default {
         jyarticle_see3_plus_pc: '标讯详情页-无限次免费查看标讯的权益',
         pc_article_original_one: '请填写以下信息升级大会员获得更多查看原文链接权限,同时可查看超前商机、联系人电话,85%用户已升级!',
         pc_article_original_more: '请填写以下信息升级大会员获得更多查看原文链接权限,同时可查看超前商机、联系人电话,85%用户已升级!',
+=======
+        pc_project_businessDetails:
+          '请留下联系方式,我们会尽快联系您体验大会员全部功能!'
+>>>>>>> main
       },
       sourceDescMap: {
         pc_buyer_monitor_more: '采购单位画像页-超级订阅用户申请监控更多业主',

+ 2 - 1
apps/bigmember_pc/src/components/common/ContentLayout.vue

@@ -76,7 +76,8 @@ export default {
         bigvip_subreport_month: 'jy-pc-bigmember-month-content-right', // 数据月报右侧
         bigvip_subreport_week: 'jy-pc-bigmember-week-content-right', // 数据周报右侧
         ent_ser_portrait: 'jy-pc-bigmember-entportrayal-content-right',
-        custom_unit_portrayal: 'jy-pc-bigmember-unitportrayal-content-right'
+        custom_unit_portrayal: 'jy-pc-bigmember-unitportrayal-content-right',
+        business_detail: 'jy-pc-bigmember-businessdetail-content-right' // 商机情报详情页右侧code
       },
       adList: [
         // {

+ 3 - 4
apps/bigmember_pc/src/components/forecast/ForeCast.vue

@@ -522,7 +522,6 @@ import TimeSelector from '@/components/selector/TimeSelector.vue'
 import { moneyUnit, dateFormatter } from '@/utils'
 import { tryCallHooks } from '@jianyu/easy-inject-qiankun'
 import { getPowerUrl } from '@/utils/power/redirect'
-import { getAssetsFile } from '@/utils'
 import {
   setFollowEnt,
   setCancelEnt,
@@ -579,7 +578,7 @@ export default {
       isFollow: '1',
       potenCode: 0,
       tips: '', // 空状态提示
-      tipimages: 'empty/jy-cry.png',
+      tipimages: 'jy-cry.png',
       dialog: {
         group: false
       },
@@ -1073,7 +1072,7 @@ export default {
         this.myDataObj.initTotal === 0
       ) {
         this.tips = '暂无企业情报信息,前往企业搜索关注企业'
-        this.tipimages = getAssetsFile('empty/jy-back.png')
+        this.tipimages = 'jy-back.png'
         console.info(this.tipimages)
       } else if (
         this.myDataObj &&
@@ -1081,7 +1080,7 @@ export default {
         this.myDataObj.initTotal !== 0
       ) {
         this.tips = '暂无匹配数据'
-        this.tipimages = getAssetsFile('empty/jy-back.png')
+        this.tipimages = 'jy-back.png'
       }
     },
     changeTime(data) {

+ 1 - 1
apps/bigmember_pc/src/components/push-list/PotentialList.vue

@@ -462,7 +462,7 @@ export default {
     padding: 0;
   }
   .el-dialog__body {
-    padding: 0!important;
+    padding: 0 !important;
   }
   .empty-container {
     margin-top: 60px;

+ 2 - 1
apps/bigmember_pc/src/router/router-interceptors.js

@@ -40,7 +40,8 @@ const powerCheckWhiteList = [
   'bid-board',
   'unit_portrayal_id',
   'set-password',
-  'portrayal_loading'
+  'portrayal_loading',
+  'business_detail'
 ]
 
 const regListCheck = function (regList, path) {

+ 8 - 0
apps/bigmember_pc/src/router/routers.js

@@ -246,10 +246,18 @@ export default [
     name: 'set-identity-info',
     component: () => import('@/views/accountInfo/SetIdentityInfo.vue')
   },
+<<<<<<< HEAD
   // 身份信息维护
   {
     path: '/article/:content/:id',
     name: 'article_detail',
     component: () => import('@/views/article-content/pages/Article.vue')
+=======
+  // 商机情报-详情页
+  {
+    path: '/business_detail/:id',
+    name: 'business_detail',
+    component: () => import('@/views/business/detail.vue')
+>>>>>>> main
   }
 ]

+ 18 - 1
apps/bigmember_pc/src/store/workspace.js

@@ -9,6 +9,9 @@ import projectFollow from './workspace/project-follow'
 import entFollow from './workspace/ent-follow'
 import dataReport from './workspace/data-report'
 import asideOthers from './workspace/aside-others'
+import importantNews from './workspace/important-news'
+import industryReport from './workspace/industry-report'
+import businessTodo from './workspace/business-todo'
 
 export default {
   namespaced: true,
@@ -42,6 +45,17 @@ export default {
     dataReportShow(state, getters, rootState, rootGetters) {
       const { 'user/power': power } = rootGetters
       return Array.isArray(power) && power.includes(10)
+    },
+    // 业主监控显示(超级订阅、大会员自定义版(未购买“业主监控”服务)、大会员智慧版、大会员商机版1.0、大会员专家版1.0新版/老版商机管理、企业管理服务)
+    hasOwnerMonitoring(state, getters, rootState, rootGetters) {
+      const {
+        'user/svip': svip,
+        'user/entniche': entniche,
+        'user/isNewEntNiche': newEnt,
+        'user/bigmember': bigmember,
+        'user/isEntService': entService
+      } = rootGetters
+      return svip || entniche || newEnt || bigmember || entService
     }
   },
   modules: {
@@ -55,6 +69,9 @@ export default {
     entFollow,
     dataReport,
     asideOthers,
-    customerWatcher
+    customerWatcher,
+    importantNews,
+    industryReport,
+    businessTodo
   }
 }

+ 0 - 0
apps/bigmember_pc/src/store/workspace/account-info.js


+ 123 - 0
apps/bigmember_pc/src/store/workspace/business-todo.js

@@ -0,0 +1,123 @@
+import { getBusinessTodoList, clickMessage, readMark } from '@/api/modules'
+import { getAssetsFile } from '@/utils'
+import { dateMatter } from '@/utils/'
+
+export default {
+  namespaced: true,
+  state: () => ({
+    loading: true,
+    loaded: false,
+    businessList: [],
+    todoList: [],
+    showTodo: false
+  }),
+  mutations: {
+    changeShowTodo(state, data) {
+      state.showTodo = data
+    },
+    changeBusinessList(state, list = []) {
+      if (Array.isArray(list)) {
+        state.businessList = list
+      }
+    },
+    changeTodoList(state, list = []) {
+      if (Array.isArray(list)) {
+        state.todoList = list
+      }
+    },
+    changeLoading(state, f = false) {
+      state.loading = f
+    },
+    changeLoaded(state, f = false) {
+      state.loaded = f
+    }
+  },
+  actions: {
+    async getList({ dispatch }, payload) {
+      const defaultPrams = {
+        needDealtWithCount: true,
+        msgType: 5,
+        offset: 1,
+        size: 5
+      }
+      const params = Object.assign({}, defaultPrams, payload)
+      dispatch('getMessageList', params)
+    },
+    async getMessageList({ commit }, payload) {
+      try {
+        commit('changeLoading', true)
+        commit('changeLoaded', false)
+        const {
+          busData = [],
+          needDoData = [],
+          code
+        } = await getBusinessTodoList(payload)
+        if (code === 0) {
+          if (Array.isArray(busData)) {
+            busData.forEach((v) => {
+              v.time = dateMatter(v.createTime.replace(/-/g, '/'))
+              ;(v.img = getAssetsFile('workspace/qb.png')),
+                (v.dot = v.isRead === 0)
+            })
+            commit('changeBusinessList', busData)
+          }
+          if (Array.isArray(needDoData)) {
+            needDoData.forEach((v) => {
+              v.time = dateMatter(v.createTime.replace(/-/g, '/'))
+              ;(v.img = getAssetsFile('workspace/db.png')),
+                (v.dot = v.isRead === 0)
+            })
+            commit('changeTodoList', needDoData)
+          }
+          const { needDealtWithCount } = payload
+          if (needDealtWithCount) {
+            commit('changeShowTodo', !needDoData ? false : needDoData.length)
+          }
+        }
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+      } catch (error) {
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+        console.log(error)
+      }
+    },
+    // 标记已读
+    async remarkRead({ state, commit }, payload) {
+      await clickMessage({
+        msgLogId: payload.msgLogId,
+        platform: 1
+      })
+      if (payload.isRead === 0) {
+        try {
+          payload.isRead = 1
+          const params = {
+            msgId: payload.id ? Number(payload.id) : null
+          }
+          const { data } = await readMark(params)
+          if (data === 1) {
+            if (Array.isArray(state.businessList)) {
+              state.businessList.forEach((business) => {
+                if (business.id === payload.id) {
+                  business.dot = false
+                }
+              })
+              commit('changeBusinessList', state.businessList)
+            }
+            if (Array.isArray(state.todoList)) {
+              state.todoList.forEach((todo) => {
+                if (todo.id === payload.id) {
+                  todo.dot = false
+                }
+              })
+              commit('changeTodoList', state.todoList)
+            }
+          }
+        } catch (error) {
+          console.log(error)
+        }
+      }
+    }
+  },
+  getters: {}
+}

+ 6 - 2
apps/bigmember_pc/src/store/workspace/common-use.js

@@ -35,7 +35,7 @@ export default {
   namespaced: true,
   state: () => ({
     platform: 'PC',
-    maxCount: Infinity,
+    maxCount: 8,
     dialogShow: false,
     menuInfoList: [], // 请求回来的原始数组
     allFunctionsContainsUsable: [], // 全部功能,包含可用的和不可用的(扁平化后)
@@ -122,6 +122,9 @@ export default {
       if (Array.isArray(list)) {
         state.mainFunctions = list
       }
+    },
+    setCommonMaxCount(state, num) {
+      state.maxCount = num
     }
   },
   actions: {
@@ -183,7 +186,8 @@ export default {
           }
         )
         if (code === 0 && data) {
-          commit('setCommonList', data)
+          commit('setCommonList', data.list || [])
+          commit('setCommonMaxCount', data.num)
         } else {
           commit('setCommonList', [])
         }

+ 60 - 0
apps/bigmember_pc/src/store/workspace/important-news.js

@@ -0,0 +1,60 @@
+// 要闻
+import { getWorkspaceNews } from '@/api/modules'
+
+export default {
+  namespaced: true,
+  state: () => ({
+    params: {
+      pageNum: 0,
+      pageSize: 10
+    },
+    loading: true,
+    loaded: false,
+    list: []
+  }),
+  mutations: {
+    changeList(state, list = []) {
+      if (Array.isArray(list)) {
+        state.list = list
+      }
+    },
+    changeLoading(state, f = false) {
+      state.loading = f
+    },
+    changeLoaded(state, f = false) {
+      state.loaded = f
+    }
+  },
+  actions: {
+    async getList({ state, dispatch }) {
+      const { params } = state
+      await dispatch('doRequest', params)
+    },
+    async doRequest({ commit }, payload) {
+      try {
+        commit('changeLoading', true)
+        commit('changeLoaded', false)
+        const { data = [], error_code: code } = await getWorkspaceNews(payload)
+        if (code === 0 && data.length) {
+          const list = data.map((v) => {
+            return {
+              ...v,
+              // visited,
+              _id: v._id,
+              title: v.s_title,
+              time: v.time ? v.time : 0
+            }
+          })
+          commit('changeList', list)
+        }
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+        return data || []
+      } catch (error) {
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+        console.log(error)
+      }
+    }
+  }
+}

+ 60 - 0
apps/bigmember_pc/src/store/workspace/industry-report.js

@@ -0,0 +1,60 @@
+import { getWorkspaceIndustryReport } from '@/api/modules'
+
+export default {
+  namespaced: true,
+  state: () => ({
+    params: {
+      pageNum: 0,
+      pageSize: 10
+    },
+    loading: true,
+    loaded: false,
+    list: []
+  }),
+  mutations: {
+    changeList(state, list = []) {
+      if (Array.isArray(list)) {
+        state.list = list
+      }
+    },
+    changeLoading(state, f = false) {
+      state.loading = f
+    },
+    changeLoaded(state, f = false) {
+      state.loaded = f
+    }
+  },
+  actions: {
+    async getList({ state, dispatch }) {
+      const { params } = state
+      await dispatch('doRequest', params)
+    },
+    async doRequest({ commit }, payload) {
+      try {
+        commit('changeLoading', true)
+        commit('changeLoaded', false)
+        const { data = [], error_code: code } =
+          await getWorkspaceIndustryReport(payload)
+        if (code === 0 && data.length) {
+          const list = data.map((v) => {
+            return {
+              ...v,
+              // visited,
+              title: v.title,
+              url: v.url,
+              time: v.showTime ? v.showTime : 0
+            }
+          })
+          commit('changeList', list)
+        }
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+        return data || []
+      } catch (error) {
+        commit('changeLoading', false)
+        commit('changeLoaded', true)
+        console.log(error)
+      }
+    }
+  }
+}

+ 2 - 1
apps/bigmember_pc/src/store/workspace/message.js

@@ -54,7 +54,8 @@ export default {
         msgType: -1,
         isRead: 0,
         offset: 1,
-        size: 20
+        size: 20,
+        isfilterActive: true // P442新增参数:过滤活动类消息
       }
       dispatch('getMessageList', params)
     },

+ 32 - 20
apps/bigmember_pc/src/store/workspace/my-customer.js

@@ -21,7 +21,8 @@ export default {
     },
     loading: true,
     loaded: false,
-    list: []
+    list: [],
+    count: 0
   }),
   mutations: {
     changeList(state, list = []) {
@@ -34,6 +35,9 @@ export default {
     },
     changeLoaded(state, f = false) {
       state.loaded = f
+    },
+    changeCount(state, count) {
+      state.count = count
     }
   },
   actions: {
@@ -45,25 +49,33 @@ export default {
       try {
         commit('changeLoading', true)
         commit('changeLoaded', false)
-        const { data = {}, error_code: code } = await customerQuery(payload)
-        if (code === 0 && data && Array.isArray(data.list)) {
-          const list = data.list.slice(0, 5).map((v) => {
-            // const visited = this.pathVisited(
-            //   this.createPathItem(
-            //     '/myCustomer/*',
-            //     `id=${v.customer_id}
-            //   )
-            // )
-            return {
-              ...v,
-              // visited,
-              _id: v.customer_id,
-              title: v.customer_name,
-              unread: false,
-              time: v.updatetime ? +new Date(v.updatetime * 1000) : 0
-            }
-          })
-          commit('changeList', list)
+        const {
+          data = {},
+          list = [],
+          error_code: code
+        } = await customerQuery(payload)
+        if (code === 0) {
+          if (Array.isArray(list)) {
+            const newList = list.slice(0, 5).map((v) => {
+              // const visited = this.pathVisited(
+              //   this.createPathItem(
+              //     '/myCustomer/*',
+              //     `id=${v.customer_id}
+              //   )
+              // )
+              return {
+                ...v,
+                // visited,
+                _id: v.customer_id,
+                title: v.customer_name,
+                unread: false,
+                time: v.updatetime ? +new Date(v.updatetime * 1000) : 0
+              }
+            })
+            commit('changeList', newList)
+          }
+          // 客户监控数量
+          commit('changeCount', data?.count)
         }
         commit('changeLoading', false)
         commit('changeLoaded', true)

+ 2 - 2
apps/bigmember_pc/src/store/workspace/subscribe.js

@@ -5,7 +5,7 @@ export default {
   state: () => ({
     params: {
       pageNum: 1,
-      pageSize: 5,
+      pageSize: 10,
       format: 'table',
       area: '',
       time: ''
@@ -67,7 +67,7 @@ export default {
               _id: v._id,
               title: v.title,
               unread: false,
-              time: v.publishtime ? v.publishtime * 1000 : 0
+              time: v.publishTime ? v.publishTime * 1000 : 0
             }
           })
           // commit('changeHasKeyState', hasKey)

+ 374 - 0
apps/bigmember_pc/src/views/business/detail.vue

@@ -0,0 +1,374 @@
+<template>
+  <Layout class="business-detail-page">
+    <div class="business-header">
+      <div class="name">
+        {{ info.title }}
+      </div>
+      <div class="business-sub-row">
+        <div class="d-m-time common-time">
+          {{ dateFromNow(new Date(publishtime).getTime()) }}
+        </div>
+        <div class="business_option">
+          <div class="potential-col">
+            提前介入,把握商机,戳我查看
+            <em class="handle-em" @click="goPotentialPage">潜在项目预测</em
+            ><i class="icon_right"></i>
+          </div>
+        </div>
+      </div>
+    </div>
+    <section class="collect-info-tip" v-if="needComplete">
+      【商机情报】想获得更精准商机情报?立即<em
+        class="handle-em"
+        @click="completeInfo"
+        >完善信息</em
+      >。您也可以<em class="handle-em" @click="openCustomer">联系客服</em
+      >进行相关咨询。
+    </section>
+    <div class="business-content">
+      <section class="poten-box">
+        <div class="box-title">
+          <span class="left-line"></span>
+          <span>预测项目</span>
+        </div>
+        <div class="box-con">
+          <div class="list_name">
+            <span class="pur_company">采购单位</span>
+            <span class="list_pur_name">{{ info.buyer }}</span>
+          </div>
+          <div class="list_poten">
+            <div class="poten_unit">
+              <span class="poten_label"
+                ><span class="point"></span>预测线索</span
+              >
+              <span class="poten_name">{{
+                info.title && info.title.indexOf('】')
+                  ? info.title.substring(info.title.indexOf('】') + 1)
+                  : info.title
+              }}</span>
+            </div>
+            <div class="poten_unit mt8">
+              <span class="poten_label"
+                ><span class="point"></span>预测采购内容</span
+              >
+              <span class="poten_name">
+                <span>{{ info.purchasing }}</span>
+              </span>
+            </div>
+            <div class="poten_unit mt8">
+              <span class="poten_label">
+                <span class="point"></span>预测采购时间:
+                <span style="color: #1d1d1d">{{
+                  dateFormatter(yuceendtime, 'yyyy-MM-dd')
+                }}</span>
+              </span>
+            </div>
+          </div>
+        </div>
+      </section>
+      <section class="similar-box mt8" v-if="similarProject">
+        <div class="box-title">
+          <span class="left-line"></span>
+          <span>同类项目</span>
+        </div>
+        <div class="box-con">
+          <div class="pur_unit">
+            <span class="unit_label">同类项目:</span>
+            <span
+              class="unit_name handle-em"
+              @click="goViewDetail(similarProject.p_id)"
+              >{{ similarProject.p_orther }}</span
+            >
+          </div>
+          <div class="pur_unit mt8">
+            <span class="unit_label">联系人:</span>
+            <span class="unit_name">{{ similarProject.p_person }}</span>
+          </div>
+          <div class="pur_unit mt8">
+            <span class="unit_label">联系电话:</span>
+            <span class="unit_name">{{ similarProject.p_phone }}</span>
+          </div>
+        </div>
+      </section>
+    </div>
+    <!-- 留资弹窗 -->
+    <CollectInfo ref="collectRef"></CollectInfo>
+  </Layout>
+</template>
+
+<script>
+import Layout from '@/components/common/ContentLayout.vue'
+import CollectInfo from '@/components/collect-info/CollectInfo.vue'
+import { dateFromNow, dateFormatter } from '@/utils/'
+import { mapGetters } from 'vuex'
+import tdk from '@/utils/mixins/set-tdk.js'
+import { getBusinessDetails, isNeedCompleteInfo } from '@/api/modules/'
+export default {
+  name: 'business-opp-detail',
+  mixins: [tdk],
+  components: {
+    Layout,
+    CollectInfo
+  },
+  data() {
+    return {
+      info: {},
+      needComplete: false
+    }
+  },
+  computed: {
+    ...mapGetters('user', [
+      'bigmember' // 是否大会员
+    ]),
+    publishtime() {
+      return this.info.publishtime ? this.info.publishtime * 1000 : 0
+    },
+    yuceendtime() {
+      return this.info.yuceendtime ? this.info.yuceendtime * 1000 : 0
+    },
+    similarProject() {
+      return this.info.results && this.info.results[0]
+        ? this.info.results[0]
+        : {}
+    }
+  },
+  created() {
+    this.isNeedComplete()
+    this.getDetailInfo()
+  },
+  mounted() {
+    window.openCustomer = this.openCustomer
+  },
+  methods: {
+    dateFromNow,
+    dateFormatter,
+    setTdkInfo() {
+      const name = this.info.title
+      this.setPageTdkToView({
+        title: `${name}招标采购_中标信息 - 剑鱼标讯`,
+        keywords: `${name} ,${name} 招投标,${name} 招标采购,${name}中标信息,${name}通讯录,剑鱼标讯`,
+        description: `剑鱼标讯为您提供${name}相关的工商企业信息及招投标、中标信息服务,涵盖工商企业信息、企业通讯录、公司中标信息、项目动态、年度项目统计、月度中标金额统计、市场区域及客户分布等一系列相关信息服务,全面了解${name},就上剑鱼标讯官网。`
+      })
+    },
+    // 是否需要完善信息
+    async isNeedComplete() {
+      const { error_code: code, data } = await isNeedCompleteInfo()
+      if (code === 0) {
+        this.needComplete = !!data
+      }
+    },
+    // 获取信息详情
+    async getDetailInfo() {
+      const id = this.$route.params?.id || ''
+      const { error_code: code, data = {} } = await getBusinessDetails({ id })
+      if (code === 0 && data) {
+        this.info = data
+        this.setTdkInfo()
+      }
+    },
+    goViewDetail(id) {
+      const routeUrl = this.$router.resolve({
+        path: '/pro_follow_detail?sid=' + id
+      })
+      return window.open(routeUrl.href, '_blank')
+    },
+    // 完善信息
+    completeInfo() {
+      window.location.href =
+        '/swordfish/frontPage/user/sess/set_favorite?source=pc_project_businessDetails_improve'
+    },
+    // 联系客服
+    openCustomer() {
+      this.contactCustomer(this)
+    },
+    // 跳转潜在项目预测(无权限用户引导大会员留资,大会员引导跳转到潜在项目预测页面。)
+    goPotentialPage() {
+      if (this.bigmember) {
+        window.open('/swordfish/page_big_pc/forecast_list')
+      } else {
+        this.$refs.collectRef.isNeedSubmit('pc_project_businessDetails')
+      }
+    }
+  }
+}
+</script>
+<style lang="scss">
+.business-detail-page {
+  > .content-right.ad-container {
+    width: 200px !important;
+  }
+}
+</style>
+<style lang="scss" scoped>
+.business-detail-page {
+  margin: 32px auto;
+  .business-header {
+    position: relative;
+    padding: 24px 40px;
+    background: #fff;
+    line-height: 36px;
+    border-radius: 8px;
+    .name {
+      font-size: 24px;
+      line-height: 36px;
+      color: #252627;
+    }
+    .business-sub-row {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-top: 12px;
+    }
+    .common-time {
+      margin-left: 8px;
+      font-size: 12px;
+      font-family: Microsoft YaHei-Regular, Microsoft YaHei;
+      font-weight: 400;
+      color: #999999;
+      line-height: 18px;
+    }
+    .business_option {
+      display: flex;
+      align-items: center;
+    }
+    .potential-col {
+      padding: 4px 12px;
+      border-radius: 4px;
+      border: 1px solid #87dfea;
+      background: #eaf8fa;
+      font-size: 14px;
+      line-height: 22px;
+      margin-right: 16px;
+    }
+    .icon_right {
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      background: url('~@/assets/images/icon/icon_right2.png') no-repeat center;
+      background-size: contain;
+      margin-left: 4px;
+    }
+  }
+  .collect-info-tip {
+    font-size: 16px;
+    color: #1d1d1d;
+    line-height: 24px;
+    padding: 16px 0 16px 40px;
+    background: #fff url('~@/assets/images/business/tip-bg.png') no-repeat
+      center right;
+    background-size: contain;
+    margin-top: 16px;
+    border-radius: 8px;
+  }
+  .business-content {
+    background: #fff;
+    border-radius: 8px;
+    padding: 32px 40px 32px 0;
+    margin-top: 16px;
+
+    .poten-box {
+      .list_name {
+        display: flex;
+        align-items: center;
+        margin-bottom: 12px;
+
+        .pur_company {
+          margin-right: 8px;
+          padding: 2px 8px;
+          width: 68px;
+          height: 24px;
+          background: rgba(245, 101, 0, 0.1);
+          border-radius: 2px;
+          font-size: 13px;
+          font-weight: 400;
+          text-align: center;
+          color: #f56500;
+          line-height: 20px;
+        }
+
+        .list_pur_name {
+          color: #171826;
+          font-size: 16px;
+          line-height: 24px;
+        }
+      }
+
+      .list_poten {
+        display: flex;
+        flex-direction: column;
+
+        .poten_unit {
+          display: flex;
+          flex-direction: column;
+
+          .poten_label {
+            display: flex;
+            align-items: center;
+            font-size: 14px;
+            color: #999999;
+            line-height: 22px;
+
+            .point {
+              display: flex;
+              margin-right: 9px;
+              width: 4px;
+              height: 4px;
+              background: #ececec;
+              border-radius: 50%;
+            }
+          }
+
+          .poten_name {
+            margin-left: 12px;
+            font-size: 14px;
+            color: #1d1d1d;
+            line-height: 22px;
+          }
+        }
+      }
+    }
+
+    .similar-box {
+      .pur_unit {
+        font-size: 14px;
+        line-height: 22px;
+        .unit_label {
+          display: inline-block;
+          color: #999;
+          width: 70px;
+          text-align: right;
+        }
+        .unit_name {
+          color: #1d1d1d;
+        }
+      }
+    }
+    .box-title {
+      display: flex;
+      align-items: center;
+      font-size: 20px;
+      color: #1d1d1d;
+
+      .left-line {
+        display: inline-block;
+        background: #2abed1;
+        width: 3px;
+        height: 24px;
+        border-radius: 0 2px 2px 0;
+        margin-right: 37px;
+      }
+    }
+    .box-con {
+      padding: 8px 40px;
+      margin-top: 8px;
+    }
+    .mt8 {
+      margin-top: 8px;
+    }
+  }
+  .handle-em {
+    color: #2abed1 !important;
+    cursor: pointer;
+  }
+}
+</style>

+ 87 - 0
apps/bigmember_pc/src/views/workspace/components/AccountInfo.vue

@@ -0,0 +1,87 @@
+<template>
+  <section class="user-info-card">
+    <h4 class="user-info-title">
+      <span class="user-info-title-fireworks"></span>
+      <span class="user-info-title-text highlight-text"
+        >欢迎您!<i class="user-nickname">{{ accountInfo.nickName }}</i></span
+      >
+    </h4>
+    <p class="user-info-line user-info-type">
+      <span class="user-info-line-label">账号类型:</span>
+      <span class="user-info-line-value">{{ accountInfo.vipType }}</span>
+    </p>
+    <p class="user-info-line user-info-time" v-if="accountInfo.vipEntTime">
+      <span class="user-info-line-label">会员服务到期时间:</span>
+      <span class="user-info-line-value">{{ accountInfo.vipEntTime }}</span>
+    </p>
+  </section>
+</template>
+
+<script>
+import { getUserAccountShow } from '@/api/modules/'
+export default {
+  name: 'UserAccount',
+  data() {
+    return {
+      accountInfo: {
+        nickName: '',
+        vipType: '',
+        vipEntTime: ''
+      }
+    }
+  },
+  mounted() {
+    this.getAccount()
+  },
+  methods: {
+    async getAccount() {
+      const { data } = await getUserAccountShow()
+      if (data) {
+        const { nickname, vipType, vipEntTime } = data
+        this.accountInfo.nickName = nickname
+        this.accountInfo.vipType = vipType
+        this.accountInfo.vipEntTime = vipEntTime
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.user-info-card {
+  padding: 12px 20px;
+  margin-bottom: 16px;
+  border-radius: 8px;
+  background: #fff;
+  .user-info-title {
+    display: flex;
+    align-items: center;
+    margin-bottom: 6px;
+    &-fireworks {
+      display: inline-block;
+      width: 24px;
+      height: 24px;
+      margin-right: 8px;
+      background: url('~@/assets/images/icon/fireworks.png') no-repeat center;
+      background-size: contain;
+    }
+    &-text {
+      font-size: 16px;
+      line-height: 24px;
+    }
+  }
+  .user-info-line {
+    font-size: 14px;
+    line-height: 22px;
+    &-label {
+      color: #999999;
+    }
+    &-value {
+      color: #1d1d1d;
+    }
+  }
+  .user-info-type {
+    margin-bottom: 4px;
+  }
+}
+</style>

+ 46 - 0
apps/bigmember_pc/src/views/workspace/components/AnalysisReport.vue

@@ -0,0 +1,46 @@
+<template>
+  <ListCard
+    class="news-list"
+    :list="list"
+    title="分析报告"
+    @clickListItem="clickListItem"
+    @linkMore="linkMore"
+    :loading="loading"
+    :loaded="loaded"
+  >
+    <div slot="empty-content" class="empty-content">
+      <p>暂无数据</p>
+    </div>
+  </ListCard>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+import ListCard from '../ui/ListCard'
+
+export default {
+  name: 'AnalysisReport',
+  components: {
+    ListCard
+  },
+  computed: {
+    ...mapState({
+      loading: (state) => state.workspace.industryReport.loading,
+      loaded: (state) => state.workspace.industryReport.loaded,
+      list: (state) => state.workspace.industryReport.list
+    })
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    ...mapActions('workspace/industryReport', ['getList']),
+    clickListItem(item) {
+      window.open(item.url)
+    },
+    linkMore() {
+      window.open('/hybg/')
+    }
+  }
+}
+</script>

+ 193 - 0
apps/bigmember_pc/src/views/workspace/components/BusinessToDo.vue

@@ -0,0 +1,193 @@
+<template>
+  <section class="business-todo-card">
+    <header class="card-header">
+      <div class="card-header-tabs">
+        <span
+          :class="{
+            active: activeName === tab.type,
+            only: computedTabs.length === 1
+          }"
+          v-for="tab in computedTabs"
+          :key="tab.type"
+          @click="onTabClick(tab.type)"
+          >{{ tab.name }}</span
+        >
+      </div>
+      <div class="card-header-more" v-if="showMore" @click="linkMore">
+        <span class="more-text">更多</span>
+        <span class="el-icon-jy-blue-more"></span>
+      </div>
+    </header>
+    <transition name="el-fade-in-linear">
+      <div v-loading="loading">
+        <main class="card-main" v-show="activeName === 5">
+          <div class="chat-list">
+            <ChatItem
+              v-for="(item, index) in businessList"
+              :key="index"
+              v-bind="item"
+              @click="onBusinessItem(item)"
+            ></ChatItem>
+          </div>
+          <div class="empty-wrapper" v-show="!businessList.length && loaded">
+            <Empty class="empty-mini" direction="row" :mtb60="false">
+              <slot name="empty-content">暂无数据</slot>
+            </Empty>
+          </div>
+        </main>
+        <main class="card-main" v-show="activeName === 11">
+          <div class="chat-list">
+            <ChatItem
+              v-for="(item, index) in todoList"
+              :key="index"
+              v-bind="item"
+              @click="onBusinessItem(item)"
+            ></ChatItem>
+          </div>
+          <div class="empty-wrapper" v-show="!todoList.length && loaded">
+            <Empty class="empty-mini" direction="row" :mtb60="false">
+              <slot name="empty-content">暂无数据</slot>
+            </Empty>
+          </div>
+        </main>
+      </div>
+    </transition>
+  </section>
+</template>
+
+<script>
+import ChatItem from '../ui/ChatItem.vue'
+import Empty from '@/components/common/Empty.vue'
+import { mapState, mapActions } from 'vuex'
+import { debounce } from 'lodash'
+
+export default {
+  name: 'BusinessToDo',
+  components: {
+    ChatItem,
+    Empty
+  },
+  data() {
+    return {
+      tabs: [
+        { name: '商机情报', type: 5 },
+        { name: '待办', type: 11 }
+      ],
+      activeName: 5
+    }
+  },
+  computed: {
+    ...mapState({
+      loading: (state) => state.workspace.businessTodo.loading,
+      loaded: (state) => state.workspace.businessTodo.loaded,
+      showTodo: (state) => state.workspace.businessTodo.showTodo,
+      businessList: (state) => state.workspace.businessTodo.businessList,
+      todoList: (state) => state.workspace.businessTodo.todoList
+    }),
+    showMore() {
+      const businessType = this.activeName === 5
+      const todoLength = this.todoList.length
+      const businessLength = this.businessList.length
+      return businessType ? businessLength : todoLength
+    },
+    // P442需求:待办为空时,不展示该分类
+    computedTabs() {
+      return this.tabs.filter((item) => {
+        return this.showTodo ? item : item.type !== 11
+      })
+    }
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    ...mapActions('workspace/businessTodo', ['getList', 'remarkRead']),
+    linkMore() {
+      const type = this.activeName
+      window.open(`/swordfish/frontPage/messageCenter/sess/index?type=${type}`)
+    },
+    onTabClick(msgType) {
+      this.activeName = msgType
+    },
+    onBusinessItem: debounce(async function (item) {
+      try {
+        await this.remarkRead(item)
+        window.open(item.link)
+      } catch (error) {
+        window.open(item.link)
+      }
+    }, 300)
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@include diy-icon('blue-more', 16, 16);
+.business-todo-card {
+  flex: 1;
+  max-width: 49%;
+  border-radius: 8px;
+  background: #fff;
+  box-shadow: 0px 0px 18px 0px rgba(0, 0, 0, 0.02);
+  .card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 10px 16px 10px 0;
+    &-tabs {
+      span {
+        display: inline-block;
+        padding: 0 16px;
+        font-size: 18px;
+        line-height: 28px;
+        color: #686868;
+        cursor: pointer;
+      }
+      .active {
+        position: relative;
+        color: #1d1d1d;
+        &::after {
+          position: absolute;
+          content: '';
+          left: 16px;
+          right: 16px;
+          bottom: -4px;
+          height: 2px;
+          background: $color_main;
+        }
+      }
+      .only {
+        color: #1d1d1d;
+        &::after {
+          display: none;
+        }
+      }
+    }
+    &-more {
+      display: flex;
+      align-items: center;
+      font-size: 14px;
+      color: $color_main;
+      line-height: 22px;
+      cursor: pointer;
+      .more-text {
+        margin-right: 4px;
+      }
+    }
+  }
+  .card-main {
+    padding: 0 12px 16px;
+    min-height: 246px;
+  }
+  ::v-deep {
+    .chat-item {
+      .chat-item-l {
+        width: 32px;
+        height: 32px;
+        background: transparent;
+        margin-right: 12px;
+      }
+    }
+  }
+}
+</style>

+ 97 - 0
apps/bigmember_pc/src/views/workspace/components/ChatList.vue

@@ -0,0 +1,97 @@
+<template>
+  <section class="chat-card">
+    <header class="chat-card-header">
+      <h4>聊天</h4>
+    </header>
+    <main class="chat-card-main">
+      <div class="chat-list">
+        <ChatItem
+          v-for="(item, index) in list"
+          :key="index"
+          v-bind="item"
+          @click="onClickItem(item)"
+        ></ChatItem>
+      </div>
+    </main>
+  </section>
+</template>
+
+<script>
+import ChatItem from '../ui/ChatItem'
+import { getUserSessionList } from '@/api/modules/'
+import { dateFormatter } from '@/utils/'
+export default {
+  name: 'ChatList',
+  components: {
+    ChatItem
+  },
+  data() {
+    return {
+      list: []
+    }
+  },
+  mounted() {
+    this.getList()
+  },
+  methods: {
+    async getList() {
+      const { data } = await getUserSessionList({
+        userType: 2,
+        queryType: 2,
+        page: 1,
+        size: 3
+      })
+      if (data) {
+        const list = data.map((v) => {
+          if (v.type === 3) {
+            v.content = '[图片]'
+          } else if (v.type === 4) {
+            v.content = '[附件]'
+          }
+          return {
+            id: v.userId,
+            userType: v.userType,
+            title: v.name,
+            content: v.content
+              ? v.content
+                  .replace(/<img.*?src=[\"|\']?(.*?)[\"|\']*?>/g, '[图片]')
+                  .replace(/<[^>]+>/g, '')
+              : '',
+            img: v.headimg,
+            name: v.headimg ? '' : this.getName(v.name),
+            time: v.create_time
+              ? dateFormatter(v.create_time * 1000, 'yyyy-MM-dd')
+              : ''
+          }
+        })
+        this.list = list
+      }
+    },
+    getName(name) {
+      if (!name) return
+      return name.slice(-2)
+    },
+    onClickItem(item) {
+      window.open(
+        `/page_pc_social/customer?userId=${item.id}&userType=${item.userType}`
+      )
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.chat-card {
+  margin-bottom: 16px;
+  border-radius: 8px;
+  background: #fff;
+  &-header {
+    padding: 12px 20px 8px;
+    font-size: 18px;
+    line-height: 28px;
+  }
+  .chat-list {
+    padding: 0 12px 8px;
+  }
+}
+</style>

+ 35 - 10
apps/bigmember_pc/src/views/workspace/components/CommonUse.vue

@@ -1,7 +1,14 @@
 <template>
-  <WorkspaceCard class="work-common" title="常用功能">
+  <WorkspaceCard class="work-common">
+    <span slot="header-title">
+      我的常用
+      <span class="header-title-count"
+        >(<i class="highlight-text">{{ commonList.length }}</i
+        >/{{ maxCount }})</span
+      >
+    </span>
     <span slot="header-right" class="header-right-set" @click="setCommonFun"
-      ><i class="icon-set-img"></i> 设置</span
+      ><i class="icon-set-img"></i> 自定义</span
     >
     <div class="common-lists">
       <div
@@ -78,7 +85,10 @@
         @scroll="handleScroll($event)"
       >
         <div class="added-function">
-          <h3 class="added-title">已添加({{ addedList.length }})</h3>
+          <h3 class="added-title">
+            已添加(<span class="highlight-text">{{ addedList.length }}</span
+            >/{{ maxCount }})
+          </h3>
           <transition-group
             class="added-container"
             name="drag"
@@ -210,7 +220,8 @@ export default {
       enterIndex: '',
       tabActive: 0,
       tabFixed: false,
-      isScrollAnchor: true
+      isScrollAnchor: true,
+      calcList: []
     }
   },
   computed: {
@@ -415,6 +426,9 @@ export default {
       this.updateMainFunStatus(item)
     },
     onAddFun(item) {
+      if (this.addedList.length >= this.maxCount) {
+        return this.$toast(`已添加满${this.maxCount}个,请移除部分功能后再添加`)
+      }
       item.status = true
       this.addedList.unshift(item)
       this.updateMainFunStatus(item)
@@ -746,6 +760,14 @@ $main: #2cb7ca;
       }
     }
   }
+  .header-title-count {
+    font-size: 14px;
+    line-height: 22px;
+    color: #686868;
+  }
+  .card-content {
+    padding: 4px 16px 8px;
+  }
 }
 .icon-box-container {
   display: flex;
@@ -793,18 +815,21 @@ $main: #2cb7ca;
   cursor: pointer;
 }
 .common-lists {
-  padding: 0 20px;
+  height: 112px;
   display: flex;
+  overflow: hidden;
   flex-wrap: wrap;
   .list-item,
   .list-add {
-    width: 120px;
-    padding: 18px 0 24px;
+    width: 110px;
+    height: 112px;
+    padding: 8px 0;
     display: flex;
     flex-direction: column;
     align-items: center;
     text-align: center;
     cursor: pointer;
+    flex-shrink: 0;
   }
   .list-item {
     // flex: 1;
@@ -820,9 +845,9 @@ $main: #2cb7ca;
     font-size: 14px;
     line-height: 20px;
     color: #1d1d1d;
-    @media only screen and (max-width: 1280px) {
-      font-size: 12px;
-    }
+    // @media only screen and (max-width: 1280px) {
+    //   font-size: 12px;
+    // }
   }
   .item-img {
     width: 44px;

+ 3 - 0
apps/bigmember_pc/src/views/workspace/components/MessageTips.vue

@@ -111,6 +111,9 @@ export default {
   .el-carousel__container {
     height: 141px;
   }
+  .card-content{
+    padding: 2px 20px 16px;
+  }
 }
 
 .sub-text {

+ 222 - 0
apps/bigmember_pc/src/views/workspace/components/MyEquityList.vue

@@ -0,0 +1,222 @@
+<template>
+  <section class="my-equity-list">
+    <header class="card-header">我的</header>
+    <main class="card-main">
+      <EquityItem
+        v-for="(item, index) in calcList"
+        :key="index"
+        v-bind="item"
+        v-show="item.show"
+        @click="onClickItem(item)"
+      ></EquityItem>
+    </main>
+  </section>
+</template>
+
+<script>
+import { getWorkspaceEquityCount } from '@/api/modules/'
+import { mapGetters } from 'vuex'
+import EquityItem from '../ui/EquityItem.vue'
+import { getAssetsFile } from '@/utils'
+import { tryCallHooks } from '@jianyu/easy-inject-qiankun'
+
+export default {
+  name: 'MyEquityList',
+  components: {
+    EquityItem
+  },
+  data() {
+    return {
+      list: [
+        {
+          name: '项目进度监控',
+          count: 0,
+          unit: '个',
+          background: 'linear-gradient(#D2EEFB, #EBF6FB)',
+          icon: getAssetsFile('workspace/my-project.png'),
+          noText: '前往添加',
+          link: '/swordfish/page_big_pc/free/project_progress',
+          addLink: '/jylab/supsearch/index.html',
+          appType: 'outer',
+          addAppType: 'iframe',
+          openType: '_blank',
+          addOpenType: '_self'
+        },
+        {
+          name: '企业情报监控',
+          count: 0,
+          unit: '个',
+          background: 'linear-gradient(#D2FDEE, #ECFCF6)',
+          icon: getAssetsFile('workspace/my-gen.png'),
+          noText: '前往添加',
+          link: '/swordfish/page_big_pc/free/ent_follow',
+          addLink: '/jylab/entSearch/index.html',
+          appType: 'outer',
+          addAppType: 'iframe',
+          openType: '_blank',
+          addOpenType: '_self'
+        },
+        {
+          name: '收藏的标讯',
+          count: 0,
+          unit: '条',
+          background: 'linear-gradient(#FFEBD7, #FFF8F1)',
+          icon: getAssetsFile('workspace/my-collect.png'),
+          noText: '前往收藏',
+          link: '/swordfish/frontPage/collection/sess/index',
+          addLink: '/jylab/supsearch/index.html',
+          appType: 'outer',
+          addAppType: 'iframe',
+          openType: '_blank',
+          addOpenType: '_self'
+        },
+        {
+          name: '业主监控',
+          count: 0,
+          unit: '个',
+          background: 'linear-gradient(#FFE2DE, #FFF6F4)',
+          icon: getAssetsFile('workspace/my-customer.png'),
+          noText: '前往添加',
+          link: '/swordfish/page_big_pc/my_client',
+          addLink: '/jylab/purSearch/index.html',
+          appType: 'outer',
+          addAppType: 'iframe',
+          openType: '_blank',
+          addOpenType: '_self'
+        },
+        {
+          name: '已认领项目',
+          count: 0,
+          unit: '个',
+          background: 'linear-gradient(#FFE2DE, #FFF6F4)',
+          icon: getAssetsFile('workspace/my-claim.png'),
+          noText: '前往认领',
+          link: '/succbi/nzj/app/nzj.app/nzj_claim.spg',
+          addLink: '/succbi/nzj/app/nzj.app/nzj_search_1.spg',
+          appType: 'iframe',
+          addAppType: 'iframe',
+          addOpenType: '_self'
+        }
+      ],
+      my: {
+        claimCount: 0,
+        projectFollowCount: 0,
+        entFollowCount: 0,
+        collectCount: 0,
+        customerCount: 0
+      }
+    }
+  },
+  computed: {
+    ...mapGetters('workspace', ['hasMemberNJPower', 'hasOwnerMonitoring']),
+    calcList() {
+      const {
+        claimCount,
+        projectFollowCount,
+        entFollowCount,
+        collectCount,
+        customerCount
+      } = this.my
+      const list = this.list.map((v) => {
+        switch (v.name) {
+          case '业主监控':
+            v.show = this.hasOwnerMonitoring
+            v.count = customerCount
+            break
+          case '已认领项目':
+            v.show = this.hasMemberNJPower
+            v.count = claimCount
+            break
+          case '项目进度监控':
+            v.show = true
+            v.count = projectFollowCount
+            break
+          case '企业情报监控':
+            v.show = true
+            v.count = entFollowCount
+            break
+          case '收藏的标讯':
+            v.show = true
+            v.count = collectCount
+            break
+        }
+        return {
+          ...v
+        }
+      })
+      return list
+    }
+  },
+  created() {
+    this.getWorkspaceEquity()
+    console.log(this.hasOwnerMonitoring)
+  },
+  methods: {
+    async getWorkspaceEquity() {
+      const { data } = await getWorkspaceEquityCount()
+      if (data) {
+        this.my.claimCount = data.claimCount || 0
+        this.my.projectFollowCount = data.projectFollowCount || 0
+        this.my.entFollowCount = data.entFollowCount || 0
+        this.my.collectCount = data.collectCount || 0
+        this.my.customerCount = data.ownerMonitoring || 0
+      }
+    },
+    onClickItem(item) {
+      /*
+       * 前往认领to拟在建搜索(bi)
+       * 客户监控to采购单位搜索(iframe)
+       * 前往收藏to招标采购搜索(iframe)
+       * 企业情报监控to企业搜索(iframe)
+       * 项目进度监控to招标采购搜索(iframe)
+       */
+      tryCallHooks({
+        fn: () => {
+          this.$BRACE.methods.open({
+            route: {
+              link: item.count ? item.link : item.addLink,
+              appType: item.count ? item.appType : item.addAppType,
+              openType: item.count ? item.openType : item.addOpenType
+            }
+          })
+        },
+        spareFn: () => {
+          const url = item.count ? item.link : encodeURIComponent(item.addLink)
+          if (item.count) {
+            if (item.openType === '_blank') {
+              window.open(url)
+            } else {
+              location.href = url
+            }
+          } else {
+            if (item.addOpenType === '_blank') {
+              window.open(url)
+            } else {
+              location.href = url
+            }
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@include diy-icon('blue-more', 16, 16);
+.my-equity-list {
+  margin-top: 16px;
+  border-radius: 8px;
+  background: #fff;
+  .card-header {
+    padding: 12px 20px 8px;
+    font-size: 18px;
+    line-height: 28px;
+  }
+  .card-main {
+    display: flex;
+    align-items: center;
+    padding: 8px 20px 16px;
+  }
+}
+</style>

+ 50 - 0
apps/bigmember_pc/src/views/workspace/components/NewsList.vue

@@ -0,0 +1,50 @@
+<template>
+  <ListCard
+    class="news-list"
+    :list="list"
+    title="要闻"
+    @clickListItem="clickListItem"
+    @linkMore="linkMore"
+    :loading="loading"
+    :loaded="loaded"
+  >
+    <div slot="empty-content" class="empty-content">
+      <p>暂无数据</p>
+    </div>
+  </ListCard>
+</template>
+
+<script>
+import { mapState, mapActions } from 'vuex'
+import ListCard from '../ui/ListCard'
+
+export default {
+  name: 'NewsList',
+  components: {
+    ListCard
+  },
+  computed: {
+    ...mapState({
+      loading: (state) => state.workspace.importantNews.loading,
+      loaded: (state) => state.workspace.importantNews.loaded,
+      list: (state) => state.workspace.importantNews.list
+    })
+  },
+  created() {
+    this.getList()
+  },
+  methods: {
+    ...mapActions('workspace/importantNews', ['getList']),
+    resolveLink(link) {
+      const { href } = this.$router.resolve(link)
+      return href
+    },
+    clickListItem(item) {
+      window.open(`/jySite/${item._id}.html`)
+    },
+    linkMore() {
+      window.open('/jySchool/zbjq/index.html')
+    }
+  }
+}
+</script>

+ 2 - 2
apps/bigmember_pc/src/views/workspace/components/SubscribeList.vue

@@ -2,7 +2,7 @@
   <ListCard
     class="subscribe-list"
     :list="subscribeList"
-    title="我的订阅信息"
+    title="订阅推送"
     @clickListItem="clickListItem"
     @linkMore="linkMore"
     :loading="loading"
@@ -56,7 +56,7 @@ export default {
       hasKey: (state) => state.workspace.subscribe.hasKey, // 是否有订阅关键词
       loading: (state) => state.workspace.subscribe.loading,
       loaded: (state) => state.workspace.subscribe.loaded,
-      subscribeList: (state) => state.workspace.subscribe.list.slice(0, 5)
+      subscribeList: (state) => state.workspace.subscribe.list.slice(0, 10)
     })
   },
   data() {

+ 44 - 26
apps/bigmember_pc/src/views/workspace/dashboard.vue

@@ -2,10 +2,6 @@
   <el-container class="workspace-dashboard">
     <el-main>
       <CommonUse class="main-module"></CommonUse>
-      <BusinessProfile
-        v-if="businessProfileShow"
-        class="main-module"
-      ></BusinessProfile>
       <div
         class="main-module card-list-module"
         v-for="(moduleList, floor) in mainModuleList"
@@ -17,11 +13,18 @@
           :is="name"
         ></component>
       </div>
-      <div class="main-module card-list-module" v-if="dataReportShow">
+      <MyEquityList></MyEquityList>
+      <!-- <div class="main-module card-list-module" v-if="dataReportShow">
         <DataReport></DataReport>
-      </div>
+      </div> -->
+      <BusinessProfile
+        v-if="businessProfileShow"
+        class="main-module"
+      ></BusinessProfile>
     </el-main>
     <el-aside width="369px">
+      <AccountInfo></AccountInfo>
+      <ChatList></ChatList>
       <MessageTips class="aside-module"></MessageTips>
       <AsideOthers class="aside-module"></AsideOthers>
     </el-aside>
@@ -37,17 +40,23 @@ import { Container, Aside, Main } from 'element-ui'
 import MessageTips from './components/MessageTips.vue'
 import CommonUse from './components/CommonUse.vue'
 import SubscribeList from './components/SubscribeList.vue'
-import MyCollections from './components/MyCollections.vue'
-import ProjectFollow from './components/ProjectFollow.vue'
-import EntFollow from './components/EntFollow.vue'
-import DataReport from './components/DataReport.vue'
+// import MyCollections from './components/MyCollections.vue'
+// import ProjectFollow from './components/ProjectFollow.vue'
+// import EntFollow from './components/EntFollow.vue'
+// import DataReport from './components/DataReport.vue'
 import AsideOthers from './components/AsideOthers.vue'
-import ClaimList from './components/ClaimList.vue'
+// import ClaimList from './components/ClaimList.vue'
 import ActivityDialog from '@/components/ad/activity-dialog.vue'
 import GuideIntroDialog from '@/components/ad/guide-intro-dialog.vue'
+import AccountInfo from './components/AccountInfo.vue'
+import ChatList from './components/ChatList.vue'
+import BusinessToDo from './components/BusinessToDo.vue'
+import NewsList from './components/NewsList.vue'
+import AnalysisReport from './components/AnalysisReport.vue'
+import MyEquityList from './components/MyEquityList.vue'
 const BusinessProfile = () => import('./components/BusinessProfile.vue')
-const MyCustomer = () => import('./components/MyCustomer.vue')
-const CustomerWatcher = () => import('./components/CustomerWatcher.vue')
+// const MyCustomer = () => import('./components/MyCustomer.vue')
+// const CustomerWatcher = () => import('./components/CustomerWatcher.vue')
 export default {
   name: 'WorkspaceDashboard',
   components: {
@@ -59,27 +68,36 @@ export default {
     MessageTips,
     CommonUse,
     BusinessProfile,
-    MyCustomer,
-    CustomerWatcher,
+    // MyCustomer,
+    // CustomerWatcher,
     SubscribeList,
-    MyCollections,
-    ProjectFollow,
-    DataReport,
+    // MyCollections,
+    // ProjectFollow,
+    // DataReport,
     AsideOthers,
-    EntFollow,
-    ClaimList
+    // EntFollow,
+    // ClaimList,
+    AccountInfo,
+    ChatList,
+    BusinessToDo,
+    NewsList,
+    AnalysisReport,
+    MyEquityList
   },
   computed: {
     componentsPowerMap() {
       const { myCustomerShow, customerWatcherShow, hasMemberNJPower } = this
       return {
-        ClaimList: hasMemberNJPower,
-        MyCustomer: myCustomerShow,
-        CustomerWatcher: customerWatcherShow,
+        BusinessToDo: true,
+        NewsList: true,
+        // ClaimList: hasMemberNJPower,
+        // MyCustomer: myCustomerShow,
+        // CustomerWatcher: customerWatcherShow,
         SubscribeList: true,
-        MyCollections: true,
-        ProjectFollow: true,
-        EntFollow: true
+        // MyCollections: true,
+        AnalysisReport: true
+        // ProjectFollow: true,
+        // EntFollow: true
       }
     },
     mainModuleList() {

+ 4 - 2
apps/bigmember_pc/src/views/workspace/ui/ArticleItem.vue

@@ -1,6 +1,8 @@
 <template>
   <div class="article-item" :class="{ visited }" v-on="$listeners">
-    <div class="article-item-l ellipsis visited-hd">{{ title }}</div>
+    <div class="article-item-l ellipsis visited-hd" :title="title">
+      {{ title }}
+    </div>
     <div class="article-item-r">
       <span class="red-dot" v-if="read"></span>
       <span class="r-time" v-if="time">{{
@@ -21,7 +23,7 @@ export default {
       default: ''
     },
     time: {
-      type: Number,
+      type: [Number, String],
       default: 0
     },
     read: {

+ 139 - 0
apps/bigmember_pc/src/views/workspace/ui/ChatItem.vue

@@ -0,0 +1,139 @@
+<template>
+  <div class="chat-item" v-on="$listeners">
+    <div
+      class="chat-item-l"
+      :class="{ 'chat-item-l-img': img, 'chat-item-l-dot': dot }"
+    >
+      <img v-if="img" :src="img" alt="" />
+      <span v-else>{{ name }}</span>
+      <span v-if="dot" class="l-dot"></span>
+    </div>
+    <div class="chat-item-r">
+      <div class="chat-item-r-top">
+        <span class="r-title ellipsis visited-hd">{{ title }}</span>
+        <span class="r-time" v-if="time">{{ time }}</span>
+      </div>
+      <div class="chat-item-r-bottom ellipsis" :title="content">
+        {{ content }}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ChatItem',
+  props: {
+    img: {
+      type: String,
+      default: ''
+    },
+    name: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    },
+    time: {
+      type: [String, Number],
+      default: 0
+    },
+    content: {
+      type: String,
+      default: ''
+    },
+    visited: {
+      type: Boolean,
+      default: false
+    },
+    dot: {
+      type: Boolean,
+      default: false
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.chat-item {
+  padding: 8px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  cursor: pointer;
+  &-l {
+    position: relative;
+    display: flex;
+    width: 36px;
+    height: 36px;
+    justify-content: center;
+    align-items: center;
+    margin-right: 6px;
+    font-size: 13px;
+    border-radius: 50%;
+    color: #fff;
+    flex-shrink: 0;
+    background: #2cb7ca;
+    overflow: hidden;
+    .l-dot {
+      position: absolute;
+      right: 0;
+      top: 2px;
+      width: 6px;
+      height: 6px;
+      background: #fb483d;
+      border: 1px solid #ffffff;
+      border-radius: 50%;
+    }
+  }
+  &-l-img {
+    background: transparent;
+    border: 1px solid #ececec;
+  }
+  &-l-dot {
+    overflow: unset;
+  }
+  &-r {
+    flex: 1;
+    width: 0;
+    &-top {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+    }
+    .r-title {
+      width: 70%;
+      font-size: 14px;
+      line-height: 22px;
+      color: #1d1d1d;
+    }
+    .r-time {
+      margin-left: 6px;
+      font-size: 12px;
+      line-height: 20px;
+      color: #999;
+      text-align: right;
+      white-space: nowrap;
+    }
+    &-bottom {
+      height: 18px;
+      margin-top: 2px;
+      color: #686868;
+      font-size: 12px;
+      line-height: 18px;
+    }
+  }
+  &:hover {
+    background: #eaf8fa;
+    border-radius: 8px;
+    .r-title {
+      color: #2cb7ca;
+    }
+  }
+  &:not(:last-child) {
+    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  }
+}
+</style>

+ 112 - 0
apps/bigmember_pc/src/views/workspace/ui/EquityItem.vue

@@ -0,0 +1,112 @@
+<template>
+  <div
+    class="equity-item"
+    v-on="$listeners"
+    :style="{ background: background }"
+  >
+    <el-image class="equity-item-icon" :src="icon"></el-image>
+    <div class="equity-item-box">
+      <p class="item-name">{{ name }}</p>
+      <p class="item-count" v-if="count">
+        <span class="item-count-text">{{ count }}</span>
+        <span class="item-count-unit">{{ unit }}</span>
+      </p>
+      <p class="item-href" v-else>
+        <span>{{ noText }} &gt;</span>
+      </p>
+    </div>
+  </div>
+</template>
+
+<script>
+import { Image } from 'element-ui'
+
+export default {
+  name: 'EquityItem',
+  components: {
+    [Image.name]: Image
+  },
+  props: {
+    name: {
+      type: String,
+      default: ''
+    },
+    icon: {
+      type: String,
+      default: ''
+    },
+    count: {
+      type: [Number, String],
+      default: 0
+    },
+    unit: {
+      type: String,
+      default: '个'
+    },
+    noText: {
+      type: String,
+      default: ''
+    },
+    background: {
+      type: String,
+      default: ''
+    }
+  },
+  methods: {
+    onAddClick() {
+      this.$emit('link')
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.equity-item {
+  position: relative;
+  min-width: 172px;
+  max-width: 20%;
+  height: 98px;
+  border-radius: 8px;
+  flex: 1;
+  cursor: pointer;
+  &-icon {
+    position: absolute;
+    top: 12px;
+    right: 10px;
+    width: 32px;
+    height: 32px;
+  }
+  &-box {
+    padding: 16px;
+    .item-name {
+      font-size: 14px;
+      line-height: 22px;
+      color: #686868;
+    }
+    .item-count {
+      display: flex;
+      align-items: flex-end;
+      margin-top: 8px;
+      &-text {
+        font-size: 36px;
+      }
+      &-unit {
+        font-size: 14px;
+        line-height: 22px;
+      }
+    }
+    .item-href {
+      display: flex;
+      align-items: center;
+      margin-top: 16px;
+      font-size: 16px;
+      line-height: 24px;
+      color: #1d1d1d;
+      cursor: pointer;
+    }
+  }
+  &:not(:last-child) {
+    margin-right: 12px;
+  }
+}
+</style>

+ 6 - 4
apps/bigmember_pc/src/views/workspace/ui/ListCard.vue

@@ -137,13 +137,15 @@ export default {
 }
 
 .list-item {
-  padding: 12px 0;
+  // padding: 12px 0;
+  padding: 0;
+  margin-bottom: 8px;
   display: flex;
   justify-content: space-between;
   align-items: center;
-  &:not(.last) {
-    box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset;
-  }
+  // &:not(.last) {
+  //   box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset;
+  // }
   .list-item-l {
     margin-right: 12px;
     font-size: 14px;

+ 1 - 1
apps/bigmember_pc/src/views/workspace/ui/WorkspaceCard.vue

@@ -43,7 +43,7 @@ export default {
 
 .workspace-card {
   background-color: #fff;
-  border-radius: 4px;
+  border-radius: 8px;
   box-shadow: 0px 0px 18px 0px rgba(0, 0, 0, 0.02);
 }
 .card-header {

+ 14 - 0
apps/mobile/src/api/modules/bigmember.js

@@ -118,6 +118,7 @@ export function projectDetailApi(data) {
   })
 }
 
+<<<<<<< HEAD
 // 获取采购 buyer、 中标 winner 企业基础画像信息
 export function ajaxGetMiniEntInfo(type, id) {
   return request({
@@ -129,3 +130,16 @@ export function ajaxGetMiniEntInfo(type, id) {
     })
   })
 }
+=======
+// 检查是否关注了项目
+export function projectFollowCheck (data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/bigmember/follow/project/check',
+    method: 'post',
+    data
+  })
+}
+
+
+>>>>>>> main

+ 19 - 0
apps/mobile/src/api/modules/business.js

@@ -0,0 +1,19 @@
+import request from '@/api'
+import qs from 'qs'
+
+export function getBusinessDetails(data) {
+  data = qs.stringify(data)
+  return request({
+    url: '/bigmember/project/businessDetails',
+    method: 'POST',
+    data
+  })
+}
+
+// 是否需要完善信息提示
+export function isNeedCompleteInfo () {
+  return request({
+    url: '/salesLeads/businessRetain',
+    method: 'POST'
+  })
+}

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

@@ -24,3 +24,4 @@ export * from './ent'
 export * from './dataSmt'
 export * from './jyPoints'
 export * from './invoice'
+export * from './business'

BIN
apps/mobile/src/assets/image/business/tip-bg.png


BIN
apps/mobile/src/assets/image/icon/icon-phone.png


BIN
apps/mobile/src/assets/image/icon/icon-right2.png


+ 7 - 1
apps/mobile/src/components/treasure-box/AllUse.vue

@@ -61,7 +61,8 @@ export default {
       'tabsUseableFunctions',
       'tabsAllFunctions',
       'commonFunctions',
-      'boxFeatureType'
+      'boxFeatureType',
+      'commonMaxNum'
     ]),
     currentRenderList() {
       if (this.allNeedBadge) {
@@ -211,6 +212,11 @@ export default {
     badgeHandle(item) {
       let commonArr = JSON.parse(JSON.stringify(this.commonFunctions))
       if (item.canAdd) {
+        // 常用功能超出最大限制个提示
+        if(commonArr.length >= this.commonMaxNum) {
+          this.$toast('已添加满8个,请移除部分功能后再添加')
+          return
+        }
         item.canAdd = false
         commonArr.push(item)
         this.$toast('已添加至常用功能')

+ 64 - 0
apps/mobile/src/components/treasure-box/CommonUse.vue

@@ -1,5 +1,6 @@
 <template>
   <div>
+<<<<<<< HEAD
     <template v-if="!isSettings">
       <van-loading v-if="loading" style="text-align: center" />
       <grid-text :list="commonList" :need-grid-bg="true" @openLink="openLink">
@@ -32,6 +33,34 @@
     <div class="no-data" v-if="noData && commonFunctions.length === 0">
       暂未设置常用功能
     </div>
+=======
+      <template v-if="!isSettings">
+        <van-loading v-if="loading" style="text-align: center" />
+        <grid-text
+          :list="commonList"
+          :need-grid-bg="true"
+          @openLink="openLink" >
+          <template v-if="moreGrid && !loading && commonList.length < commonMaxNum" #more-grid>
+            <div class="common-use-grid grid-bg-color clickable" @click="settingCommonFeature">
+              <!-- <AppIcon name="add-01" color="#aaa" svg size="17" /> -->
+              <img class="add-fun-icon" src="@/assets/image/icon/add-function.png" />
+              <span class="item-name">添加常用功能</span>
+            </div>
+          </template>
+        </grid-text>
+      </template>
+      <template v-if="isSettings && commonFunctions.length > 0">
+        <grid-text
+          :list="getList"
+          :need-badge="true"
+          :badge-handle="true"
+          @badgeHandle="badgeHandle"
+          :need-drag="true"
+          dragUniqueKey="settingsCommonUse"
+          @dragCallBack="dragCallBack"></grid-text>
+      </template>
+    <div  class="no-data" v-if="noData && commonFunctions.length === 0">暂未设置常用功能</div>
+>>>>>>> main
   </div>
 </template>
 
@@ -72,11 +101,20 @@ export default {
     }
   },
   computed: {
+<<<<<<< HEAD
     ...mapGetters('treasureBox', ['commonFunctions']),
     getList() {
       return this.commonFunctions
         ? JSON.parse(JSON.stringify(this.commonFunctions))
         : []
+=======
+    ...mapGetters('treasureBox', [
+      'commonFunctions',
+      'commonMaxNum'
+    ]),
+    getList () {
+      return this.commonFunctions ? JSON.parse(JSON.stringify(this.commonFunctions)) : []
+>>>>>>> main
     }
   },
   created() {
@@ -87,8 +125,34 @@ export default {
     getCommonUseList() {
       const _this = this
       this.loading = true
+<<<<<<< HEAD
       workspaceCommonUse('list', {
         platform: this.$env.platform?.toUpperCase()
+=======
+      workspaceCommonUse('list', { platform: this.$env.platform?.toUpperCase() }).then(res => {
+        const { data = [], error_code: code } = res
+        if (code === 0 && data) {
+          const maxNum = data.num || 8
+          _this.commonList = data.list || []
+          _this.commonList.forEach(temp => {
+            // 计算背景色
+            calcImgThemeColor(temp.icon).then(({ color }) => {
+              // rgba转hex
+              const hex = rgb2Hex(color)
+              const { rgba } = hexToRgba(hex, 0.08)
+              this.$set(temp, 'themeColor', rgba)
+            })
+            if (_this.isSettings) {
+              temp.canAdd = false
+            }
+          })
+          // 初始化常用组件
+          _this.$store.dispatch('treasureBox/setCommonFunction', _this.commonList)
+          _this.$store.dispatch('treasureBox/setCommonMaxNum', maxNum)
+        }
+      }).finally(() => {
+        this.loading = false
+>>>>>>> main
       })
         .then((res) => {
           const { data = [], error_code: code } = res

+ 12 - 0
apps/mobile/src/router/modules/business.js

@@ -0,0 +1,12 @@
+// 商机情报
+export default [
+  {
+    path: '/detail/:id',
+    name: 'business-detail',
+    component: () => import('@/views/business/Detail.vue'),
+    meta: {
+      header: true,
+      title: '公告信息'
+    }
+  }
+]

+ 13 - 1
apps/mobile/src/store/modules/treasureBox.js

@@ -4,7 +4,8 @@ export default {
     commonFunctions: [], // 常用功能模块
     tabsUseableFunctions: [], // tab菜单下可用功能模块
     tabsAllFunctions: [], // tab菜单下所有功能模块
-    boxFeatureType: localStorage.getItem('box_feature_type') || 'all' // 百宝箱功能类型
+    boxFeatureType: localStorage.getItem('box_feature_type') || 'all', // 百宝箱功能类型
+    commonMaxNum: 8 //常用功能限制数量
   }),
   mutations: {
     changeCommonFunction(state, list = []) {
@@ -19,6 +20,9 @@ export default {
     changeBoxFeatureType(state, value) {
       state.boxFeatureType = value
       localStorage.setItem('box_feature_type', value)
+    },
+    changeCommonMaxNum (state, value) {
+      state.commonMaxNum = value
     }
   },
   actions: {
@@ -33,6 +37,10 @@ export default {
     },
     setBoxFeatureType({ commit }, value) {
       commit('changeBoxFeatureType', value)
+    },
+    // 设置常用功能最大限制数量
+    setCommonMaxNum ({ commit }, value) {
+      commit('changeCommonMaxNum', value)
     }
   },
   getters: {
@@ -50,6 +58,10 @@ export default {
     },
     boxFeatureType(state) {
       return state.boxFeatureType || 'all'
+    },
+    // 常用功能最大限制数量
+    commonMaxNum (state) {
+      return state.commonMaxNum || 8
     }
   }
 }

+ 310 - 0
apps/mobile/src/views/business/Detail.vue

@@ -0,0 +1,310 @@
+<template>
+  <!--  商机情报详情页-->
+  <div class="j-container business-detail-page">
+    <div class="j-main">
+      <div class="business-header">
+        <div class="title">{{ info.title }}</div>
+        <div class="business-sub-row">
+          <div class="common-time">
+            {{ dateFromNow(new Date(publishtime).getTime()) }}
+          </div>
+          <div class="business_option">
+            <div class="potential-col">
+              提前介入,把握商机,戳我查看<em class="handle-em" @click="goPotentialPage">潜在项目预测</em><i class="icon_right"></i>
+            </div>
+          </div>
+        </div>
+      </div>
+      <section class="collect-info-tip" v-if="needComplete">
+        【商机情报】想获得更精准商机情报?立即<em class="handle-em" @click="completeInfo">完善信息</em>。<br>您也可以<em class="handle-em" @click="openCustomer">联系客服</em>进行相关咨询。
+      </section>
+      <div class="business-content">
+        <section class="poten-box">
+          <div class="box-title">
+            <span class="left-line"></span>
+            <span>预测项目</span>
+          </div>
+          <div class="box-con">
+            <div class="unit_row">
+              <span class="unit_label">采购单位</span>
+              <span class="list_pur_name">{{ info.buyer }}</span>
+            </div>
+            <div class="unit_row mt8">
+              <span class="unit_label"><span class="point"></span>预测线索</span>
+              <span class="poten_name">{{ info.title && info.title.indexOf('】') ? info.title.substring(info.title.indexOf('】') + 1) : info.title }}</span>
+            </div>
+            <div class="unit_row mt8">
+              <span class="unit_label"><span class="point"></span>预测采购内容</span>
+              <span class="poten_name">
+              <span>{{ info.purchasing }}</span>
+            </span>
+            </div>
+            <div class="unit_row mt8">
+              <span class="unit_label">
+                <span class="point"></span>预测采购时间:
+                <span style="color: #1d1d1d;">{{ dateFormatter(yuceendtime, 'yyyy-MM-dd') }}</span>
+              </span>
+            </div>
+          </div>
+        </section>
+        <section class="similar-box mt8">
+          <div class="box-title">
+            <span class="left-line"></span>
+            <span>同类项目</span>
+          </div>
+          <div class="box-con">
+            <div class="unit_row">
+              <span class="unit_label">同类项目:</span>
+              <span class="unit_name similar_project clickable" @click="goProjectDetail(similarProject.p_id, similarProject.p_orther)">
+                {{ similarProject.p_orther }}
+                <van-icon style="margin-left: 16px;" size="16" name="arrow" color="#C0C4CC" v-if="similarProject.p_orther"/>
+              </span>
+            </div>
+            <div class="unit_row mt8">
+              <span class="unit_label">联系人:</span>
+              <span class="unit_name">{{ similarProject.p_person }}</span>
+            </div>
+            <div class="unit_row mt8">
+              <span class="unit_label">联系电话:</span>
+              <span class="unit_name phone">
+                {{ similarProject.p_phone }}
+                <i class="icon_phone" v-if="similarProject.p_phone" @click="telHandle(similarProject.p_phone)"></i>
+              </span>
+            </div>
+          </div>
+        </section>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { dateFromNow, callPhone, dateFormatter } from '@/utils'
+import { projectFollowCheck, getBusinessDetails, isNeedCompleteInfo } from '@/api/modules/'
+import { Icon } from 'vant'
+import { mapGetters } from 'vuex'
+export default {
+  name: 'business-detail',
+  components: {
+    [Icon.name]: Icon
+  },
+  data () {
+    return {
+      info: {},
+      // 是否需要完善信息提示
+      needComplete: false
+    }
+  },
+  computed: {
+    ...mapGetters('user', [
+      'isMember',
+    ]),
+    publishtime () {
+      return this.info.publishtime ? this.info.publishtime * 1000 : 0
+    },
+    yuceendtime () {
+      return this.info.yuceendtime ? this.info.yuceendtime * 1000 : 0
+    },
+    similarProject () {
+      return this.info.results && this.info.results[0] ? this.info.results[0] : {}
+    }
+  },
+  created() {
+    this.isNeedComplete()
+    this.getDetailInfo()
+  },
+  methods: {
+    dateFromNow,
+    dateFormatter,
+    // 是否需要完善信息
+    async isNeedComplete() {
+      const { error_code: code, data } = await isNeedCompleteInfo()
+      if(code === 0) {
+        this.needComplete = !!data
+      }
+    },
+    // 获取信息详情
+    async getDetailInfo() {
+      const id = this.$route.params?.id || ''
+      const { error_code: code, data = {} } = await getBusinessDetails({ id })
+      if(code === 0 && data) {
+        this.info = data
+      }
+    },
+    // 跳转潜在项目预测(无权限用户引导大会员留资,大会员引导跳转到潜在项目预测页面。)
+    goPotentialPage () {
+      if(this.isMember) {
+        window.location.href = '/jyapp/big/page/forecast_list'
+      } else {
+        let source = 'app_project_businessDetails'
+        const { inWX, inH5 } = this.$envs
+        if (inWX) {
+          source = 'wx_project_businessDetails'
+        } else if(inH5) {
+          source = 'h5_project_businessDetails'
+        }
+        this.$leaveInfo.toLeaveInfoPage({
+          source: source
+        })
+      }
+    },
+    // 完善信息
+    completeInfo () {
+      let source = 'app_project_businessDetails_improve'
+      const { inWX, inH5 } = this.$envs
+      if (inWX) {
+        source = 'wx_project_businessDetails_improve'
+      } else if(inH5) {
+        source = 'h5_project_businessDetails_improve'
+      }
+      this.$router.push('/uersales/newuser?source=' + source)
+    },
+    // 查看项目详情
+    async goProjectDetail (id, pName) {
+      const params = {
+        sid: id
+      }
+      const  { error_code: code, data } = await projectFollowCheck(params)
+      if(code === 0) {
+        const obj = {
+          fid: data.fig ? data.fig : '',
+          sid: id
+        }
+        sessionStorage.setItem('bigvip-fid', JSON.stringify(obj))
+        if (this.$envs.inWX) {
+          location.href = '/big/wx/page/pro_follow_detail'
+        } else {
+          location.href = "/jyapp/big/page/pro_follow_detail"
+        }
+      }
+    },
+    // 电话
+    telHandle (phone) {
+      if(!phone) return
+      callPhone(phone)
+    },
+    // 联系客服
+    openCustomer () {
+      if (this.$envs.inWX) {
+        window.location.href = '/big/wx/page/customer'
+      } else {
+        window.location.href = '/jyapp/free/customer'
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.business-detail-page{
+  .business-header{
+    background: #fff;
+    padding: 24px 16px 16px;
+    margin-bottom: 8px;
+
+    .title{
+      font-size:20px;
+      line-height:30px;
+      color: #171826;
+      margin-bottom:12px;
+    }
+    .business-sub-row{
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .common-time{
+        font-size:12px;
+        color: #9B9CA3;
+      }
+      .potential-col {
+        display: flex;
+        align-items: center;
+        padding: 4px 8px;
+        border-radius: 4px;
+        border: 0.5px solid #87DFEA;
+        background: #EAF8FA;
+        font-size:12px;
+        height:26px;
+      }
+      .icon_right {
+        display: inline-block;
+        width: 10px;
+        height: 10px;
+        background: url('@/assets/image/icon/icon-right2.png') no-repeat center;
+        background-size: contain;
+        margin-left: 4px;
+      }
+    }
+  }
+  .collect-info-tip {
+    font-size:13px;
+    color: #1D1D1D;
+    line-height:20px;
+    padding: 8px 16px 8px 16px;
+    background: #fff url('@/assets/image/business/tip-bg.png')  no-repeat center right;
+    background-size:contain;
+    margin-bottom:8px;
+  }
+  .business-content{
+    .poten-box, .similar-box{
+      background: #fff;
+    }
+    .box-title{
+      padding: 16px 0 6px 16px;
+      font-size:18px;
+      line-height: 20px;
+      color: #171826;
+      display: flex;
+      align-items: center;
+      .left-line{
+        display: inline-block;
+        background: #2ABED1;
+        width: 3px;
+        height:16px;
+        border-radius: 11px;
+        margin-right: 8px;
+      }
+    }
+    .box-con{
+      padding: 16px;
+      font-size:14px;
+      color: #171826;
+      line-height:20px;
+      .unit_row {
+        display: flex;
+        flex-direction: column;
+      }
+      .unit_label{
+        font-size: 12px;
+        line-height: 18px;
+        color: #9B9CA3;
+      }
+      .similar_project{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+      }
+      .phone{
+        display: flex;
+        align-items: center;
+      }
+      .icon_phone{
+        display: inline-block;
+        width: 24px;
+        height: 24px;
+        background: url('@/assets/image/icon/icon-phone.png') no-repeat center;
+        background-size: contain;
+        margin-left: 12px;
+      }
+    }
+  }
+  .handle-em{
+    color:#2ABED1 !important;
+  }
+  .mt8{
+    margin-top:8px;
+  }
+}
+
+</style>

+ 1 - 1
apps/mobile/src/views/tabbar/Box.vue

@@ -17,7 +17,7 @@
       </div>
       <div class="work-common-box">
         <p class="mr-lr12 title-box">
-          <span class="content-title">常用功能</span>
+          <span class="content-title">我的常用</span>
           <span class="title-handle-span" @click="settingCommonFeature">
             <AppIcon name="Setting" />
             <span class="setting-text">设置</span>

+ 25 - 2
apps/mobile/src/views/treasurebox/FeatureSettings.vue

@@ -3,7 +3,8 @@
     <div class="j-main page-content">
       <div class="work-common-box common-use-module">
         <p class="pd-lr12 title-box">
-          <span class="content-title">常用功能</span>
+          <span class="content-title">我的常用</span>
+          <span class="content-count">(<em>{{ commonCount }}</em>/{{commonMaxNum}})</span>
         </p>
         <common-use :is-settings="true" :no-data="true" />
       </div>
@@ -44,7 +45,19 @@ export default {
     return {}
   },
   computed: {
+<<<<<<< HEAD
     ...mapGetters('treasureBox', ['commonFunctions'])
+=======
+    ...mapGetters('treasureBox', [
+      'commonFunctions',
+      'commonMaxNum'
+    ]),
+    commonCount () {
+      return this.commonFunctions?.length || 0
+    }
+  },
+  created () {
+>>>>>>> main
   },
   created() {},
   methods: {
@@ -106,9 +119,19 @@ $content-title-font-size: 18px;
     }
     .title-box {
       display: flex;
-      justify-content: space-between;
+      //justify-content: space-between;
       align-items: center;
+<<<<<<< HEAD
       margin-bottom: 10px;
+=======
+      margin-bottom:10px;
+      .content-count{
+        font-size:14px;
+        em {
+          color:#2ABED1;
+        }
+      }
+>>>>>>> main
     }
     .work-common-box {
       background-color: #fff;

+ 50 - 3
apps/mobile/src/views/uersales/newuser/index.vue

@@ -5,7 +5,13 @@
       <div class="title-box">
         <div class="title_top">
           <h5 class="page-title">选择您的业务标签</h5>
+<<<<<<< HEAD
           <div class="jumpto_btn" @click.stop="postNewUerData(false)">跳过</div>
+=======
+          <div v-if="!urlSource" class="jumpto_btn" @click.stop="postNewUerData(false)">
+            跳过
+          </div>
+>>>>>>> main
         </div>
         <h6 class="sub-text">{{ subtitle }}</h6>
       </div>
@@ -105,6 +111,7 @@
       </div>
     </div>
     <div class="j-button-group j-footer">
+<<<<<<< HEAD
       <button
         tag="button"
         class="j-button-confirm"
@@ -112,6 +119,10 @@
       >
         开启剑鱼之旅
       </button>
+=======
+      <button v-if="!urlSource" tag="button" class="j-button-confirm" @click.stop="postNewUerData(true)">开启剑鱼之旅</button>
+      <button v-else tag="button" class="j-button-confirm" @click.stop="submitNewUerData">提交</button>
+>>>>>>> main
     </div>
     <Dialog
       :title="dparam.setTitle"
@@ -245,7 +256,8 @@ export default {
       value: '去开启',
       label: '根据设置的推送时间发送APP消息,APP提醒设置请前往APP操作'
     },
-    timer: null
+    timer: null,
+    urlSource: '', // 路由来源
   }),
   computed: {
     showApp() {
@@ -258,6 +270,7 @@ export default {
   created() {
     callHideTab(0)
     this.getUserInfoApi()
+    this.urlSource = this.$route.query?.source || ''
   },
   mounted() {
     callHideTab(0)
@@ -564,8 +577,16 @@ export default {
      * 获取新用户数据
      * @param datas
      */
+<<<<<<< HEAD
     getNewUerSales() {
       ajaxGetIsNewUerSales({})
+=======
+    getNewUerSales () {
+      const data = {
+        source: this.urlSource || ''
+      }
+      ajaxGetIsNewUerSales(data)
+>>>>>>> main
         .then((res) => {
           if (res && res.data && res?.error_code === 0) {
             this.subtitle = res.data.intro
@@ -618,8 +639,18 @@ export default {
         }
       })
     },
+    // 提交(带有source,需要callback)
+    submitNewUerData () {
+      this.postNewUerData(true, () => {
+        history.back()
+      })
+    },
     // 提交跳过
+<<<<<<< HEAD
     postNewUerData(type) {
+=======
+    postNewUerData (type, callback) {
+>>>>>>> main
       this.setPageTrack(`点击-${type ? '开启剑鱼之旅' : '跳过'}`)
       const msgSet = {}
       this.msgTypeContent.forEach((v) => {
@@ -648,15 +679,31 @@ export default {
       // Object.keys(this.selectPopInfo).forEach(v => {
       //   codesArr[v] = this.selectPopInfo[v].select
       // })
-
+      // 添加source
+      if(this.urlSource) {
+        this.$set(codesArr, 'source', this.urlSource)
+      }
       ajaxGetappNewUerSales(codesArr)
         .then((res) => {
           if (res?.error_code === 0) {
-            this.goHomePage()
+            if(typeof callback === 'function') {
+              callback()
+            } else {
+              this.goHomePage()
+            }
           }
+<<<<<<< HEAD
         })
         .catch((e) => {
           this.goHomePage()
+=======
+        }).catch((e) => {
+          if(typeof callback === 'function') {
+            callback()
+          } else {
+            this.goHomePage()
+          }
+>>>>>>> main
           console.warn('请求跳过信息异常:', e)
         })
     },

+ 1 - 0
apps/work-bench/.env.development

@@ -6,3 +6,4 @@ VUE_APP_BASE_URL='/home'
 VUE_APP_BASE_PUBLIC='/'
 VUE_APP_BASE_SITE='https://jybx3-webtest.jydev.jianyu360.com'
 VUE_APP_BASE_LOGO='https://cdn-ali.jianyu360.com/images/swordfish/sf_01_new.png?v=0928'
+VUE_APP_SIMPLE_LOGO='https://cdn-ali.jianyu360.com/common-module/public/image/logo_new.png?v=0928'

+ 1 - 0
apps/work-bench/.env.production

@@ -6,3 +6,4 @@ VUE_APP_BASE_URL='/page_workDesktop'
 VUE_APP_BASE_PUBLIC='/page_workDesktop/'
 VUE_APP_BASE_SITE=''
 VUE_APP_BASE_LOGO='https://cdn-ali.jianyu360.com/images/swordfish/sf_01_new.png?v=0928'
+VUE_APP_SIMPLE_LOGO='https://cdn-ali.jianyu360.com/common-module/public/image/logo_new.png?v=0928'

+ 2 - 2
apps/work-bench/public/index.html

@@ -4,7 +4,7 @@
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge">
     <meta name="viewport" content="width=device-width,initial-scale=1.0">
-    <link rel="stylesheet" href="https://cdn-common.jianyu360.com/cdn/assets/iconfont/pc/23.10.26/iconfont.css">
+    <link rel="stylesheet" href="https://cdn-common.jianyu360.com/cdn/assets/iconfont/pc/24.2.21/iconfont.css">
     <title>工作台</title>
     <% if (process.env.NODE_ENV === 'production') { %>
         <script src="/common-module/public/head.js?v=<%= htmlWebpackPlugin.options.assets.version %>"></script>
@@ -15,7 +15,7 @@
       <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
     </noscript>
     <div id="app"></div>
-    <script src="https://cdn-common.jianyu360.com/cdn/assets/iconfont/pc/23.10.26/iconfont.js"></script>
+    <script src="https://cdn-common.jianyu360.com/cdn/assets/iconfont/pc/24.2.21/iconfont.js"></script>
     <script src="//cdn-common.jianyu360.com/cdn/lib/jquery/3.5.1/jquery.min.js"></script>
 
     <% if (process.env.NODE_ENV === 'production') { %>

+ 1 - 1
apps/work-bench/src/components/NavUserInfo.vue

@@ -255,7 +255,7 @@ export default {
 </style>
 <style scoped lang="scss">
 .nav-user-info-module {
-  margin-left: 48px;
+  margin-left: 20px;
   cursor: pointer;
 }
 

+ 1 - 1
apps/work-bench/src/register-app.js

@@ -106,7 +106,7 @@ export const subApps = {
     describe: '该应用包含大会员画像、推送、周报月报、个人桌面等功能',
     qiankun: {
       name: 'bigMemberSubApp',
-      entry: 'http://192.168.40.158:8081/page_big_pc/index.html',
+      entry: '/page_big_pc/index.html',
       rule: '/big',
       props: {
         inject: ({ Vue, router }) => {

+ 1 - 1
packages/work-bench-frame/packages/components/Navbar/components/item.vue

@@ -64,7 +64,7 @@ export default {
 }
 
 ::v-deep .el-badge__content.is-fixed {
-  top: -2px;
+  top: 0;
   right: 16px;
   line-height: 16px;
   background-color: #ff3a20;

+ 174 - 69
packages/work-bench-frame/packages/components/Navbar/index.vue

@@ -2,73 +2,87 @@
   <div class="navbar-group">
     <div class="logo">
       <img :src="logo" alt="logo" @click="goSiteHome">
+      <h1>剑鱼工作台</h1>
     </div>
     <div class="navbar-content-group">
-      <!--   头部搜索模块   -->
-      <navbar-search class="search-module"></navbar-search>
-      <div class="nav-group">
+      <div class="website-group">
         <div
-          class="nav-item"
-          :class="nav.class"
-          v-for="(nav, index) in navs"
+          class="website-item"
+          v-for="(site, index) in websites"
           :key="index"
-          @click="onSelectNav(nav)"
+          @click="onWebsiteNav(site)"
         >
-          <template v-if="nav.plugin">
-            <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-popover:[nav.plugin]></navbar-item>
-          </template>
-          <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-else></navbar-item>
+         <i class="iconfont" :class="site.icon"></i>
+         <span>{{site.label}}</span>
         </div>
-        <!--    提供自定义用户信息插槽    -->
-        <slot name="nav-user-info" v-bind:info="userInfo"></slot>
-        <el-popover
-          popper-class="nav-popover"
-          ref="navInfo"
-          placement="bottom"
-          trigger="hover"
-          :visible-arrow="false"
-        >
-          <div class="nav-user-info-group">
-            <navbar-item :nav="{ icon: userInfo.avatar }" mode="vertical">
-              <div class="info-group">
-                <span v-if="userInfo.name">{{ userInfo.name }}</span>
-                <span v-if="userInfo.phone">{{ userInfo.phone }}</span>
-              </div>
-            </navbar-item>
-            <button @click="onClickOut">退出登录</button>
+      </div>
+      <section class="navbar-content-group--right">
+        <!--   头部搜索模块   -->
+        <navbar-search class="search-module"></navbar-search>
+        <div class="nav-group">
+          <div
+            class="nav-item"
+            :class="nav.class"
+            v-for="(nav, index) in navs"
+            :key="index"
+            @click="onSelectNav(nav)"
+          >
+            <template v-if="nav.plugin">
+              <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-popover:[nav.plugin]></navbar-item>
+            </template>
+            <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-else></navbar-item>
           </div>
-        </el-popover>
-        <el-popover
-          popper-class="nav-popover"
-          ref="navCustomer"
-          placement="bottom"
-          trigger="hover"
-          :visible-arrow="false"
-        >
-          <div class="nav-custom-info-group">
-            <div class="info-item" v-if="hasExclusiveCustomer">
-              <div class="after-tag-box recommend-tag">推荐</div>
-              <navbar-item
-                :nav="{ label: exclusiveCustomerInfo.name, icon: 'icon-weixin_line' }"></navbar-item>
-              <navbar-item
-                class="qrcode-group"
-                :nav="{
-                label: '微信扫一扫',
-                icon: exclusiveCustomerInfo.qrcode
-              }"
-                mode="vertical"
-              >
+          <!--    提供自定义用户信息插槽    -->
+          <slot name="nav-user-info" v-bind:info="userInfo"></slot>
+          <el-popover
+            popper-class="nav-popover"
+            ref="navInfo"
+            placement="bottom"
+            trigger="hover"
+            :visible-arrow="false"
+          >
+            <div class="nav-user-info-group">
+              <navbar-item :nav="{ icon: userInfo.avatar }" mode="vertical">
+                <div class="info-group">
+                  <span v-if="userInfo.name">{{ userInfo.name }}</span>
+                  <span v-if="userInfo.phone">{{ userInfo.phone }}</span>
+                </div>
               </navbar-item>
+              <button @click="onClickOut">退出登录</button>
             </div>
-            <div class="info-item" @click="onClickCustomer('在线咨询')">
-              <navbar-item :nav="{ label: '在线咨询', icon: 'icon-kefu_xian' }" :svg="true"></navbar-item>
-            </div>
-            <div class="info-item" @click="onClickCustomer('客服热线')">
-              <navbar-item :nav="{ label: '客服热线:400-108-6670', icon: 'icon-telphone_line' }"></navbar-item>
+          </el-popover>
+          <el-popover
+            popper-class="nav-popover"
+            ref="navCustomer"
+            placement="bottom"
+            trigger="hover"
+            :visible-arrow="false"
+          >
+            <div class="nav-custom-info-group">
+              <div class="info-item" v-if="hasExclusiveCustomer">
+                <div class="after-tag-box recommend-tag">推荐</div>
+                <navbar-item
+                  :nav="{ label: exclusiveCustomerInfo.name, icon: 'icon-weixin_line' }"></navbar-item>
+                <navbar-item
+                  class="qrcode-group"
+                  :nav="{
+                  label: '微信扫一扫',
+                  icon: exclusiveCustomerInfo.qrcode
+                }"
+                  mode="vertical"
+                >
+                </navbar-item>
+              </div>
+              <div class="info-item" @click="onClickCustomer('在线咨询')">
+                <navbar-item :nav="{ label: '在线咨询', icon: 'icon-kefu_xian' }" :svg="true"></navbar-item>
+              </div>
+              <div class="info-item" @click="onClickCustomer('客服热线')">
+                <navbar-item :nav="{ label: '客服热线:400-108-6670', icon: 'icon-telphone_line' }"></navbar-item>
+              </div>
             </div>
-          </div>
-        </el-popover>
-      </div>
+          </el-popover>
+        </div>
+      </section>
     </div>
     <div v-if="showCustomer" class="customer-container">
       <iframe :src="customerUrl" name="_blank" frameborder="0" width="100%" height="100%"></iframe>
@@ -94,15 +108,15 @@ export default {
   data () {
     return {
       home: process.env.VUE_APP_BASE_SITE,
-      logo: process.env.VUE_APP_BASE_LOGO,
+      logo: process.env.VUE_APP_SIMPLE_LOGO,
       navs: [
-        {
-          label: '前往官网',
-          icon: 'icon-houtui'
-        },
+        // {
+        //   label: '前往官网',
+        //   icon: 'icon-houtui'
+        // },
         {
           label: '消息中心',
-          icon: 'icon-a-Property1gongzuozhuomianProperty2xiaoxizhongxinProperty3grey',
+          icon: 'icon-nav-message',
           badge: 0
         },
         {
@@ -111,6 +125,20 @@ export default {
           svg: true,
           plugin: 'navCustomer'
         }
+      ],
+      websites: [
+        {
+          label: '标讯主站',
+          icon: 'icon-a-Property1gray1'
+        },
+        {
+          label: '剑鱼官网',
+          icon: 'icon-a-Property1gray2'
+        },
+        {
+          label: '商情门户',
+          icon: 'icon-a-Property1gray'
+        }
       ]
     }
   },
@@ -248,6 +276,44 @@ export default {
      */
     onClickCustomer (type) {
       this.$BRACE.$emit('click-nav-customer', type)
+    },
+    /**
+     * 前往商情门户(资讯站群)
+     */
+    goSiteCms () {
+      this.$BRACE.$emit({
+        fKey: 'goSiteCms',
+        spareFn: (link) => this.$BRACE.methods.open({
+          route: { link }
+        })
+      }, '/jycms')
+    },
+    /**
+     * 前往剑鱼官网(brand)
+     */
+    goSiteBrand () {
+      this.$BRACE.$emit({
+        fKey: 'goSiteBrand',
+        spareFn: (link) => this.$BRACE.methods.open({
+          route: { link }
+        })
+      }, '/brand')
+    },
+    onWebsiteNav (nav) {
+      switch (nav.label) {
+        case '标讯主站': {
+          this.goSiteHome()
+          break
+        }
+        case '剑鱼官网': {
+          this.goSiteBrand()
+          break
+        }
+        case '商情门户': {
+          this.goSiteCms()
+          break
+        }
+      }
     }
   }
 }
@@ -529,7 +595,7 @@ export default {
   justify-content: space-between;
   min-height: 64px;
   min-width: 800px;
-  padding: 0 36px;
+  padding: 0 24px;
   box-sizing: border-box;
   background-color: #ffffff;
   box-shadow: 0px 2px 8px -1px rgba(0, 0, 0, 0.0800);
@@ -544,7 +610,8 @@ export default {
   }
 
   .logo {
-    display: inline-block;
+    display: flex;
+    align-items: center;
     width: auto;
     height: 32px;
     cursor: pointer;
@@ -552,6 +619,12 @@ export default {
     img {
       height: 100%;
     }
+    h1{
+      margin-left: 8px;
+      font-size: 18px;
+      line-height: 24px;
+      color: #2ABED1;
+    }
   }
 
   .navbar-content-group {
@@ -560,11 +633,16 @@ export default {
     justify-content: space-between;
 
     .search-module {
-      margin-left: 82px;
-      margin-right: 16px;
+      margin-left: 32px;
+      margin-right: 20px;
       flex: 1;
       max-width: 440px;
     }
+    &--right{
+      flex: 1;
+      @extend .flex-horizontal;
+      justify-content: flex-end;
+    }
   }
 
   .nav-group {
@@ -579,13 +657,40 @@ export default {
     }
 
     .nav-item + .nav-item {
-      margin-left: 48px;
+      margin-left: 20px;
+    }
+  }
+  .website-group{
+    @extend .flex-horizontal;
+    margin-left: 16px;
+    .website-item{
+      @extend .flex-horizontal;
+      padding: 6px 8px;
+      margin-right: 10px;
+      font-size: 14px;
+      border-radius: 6px;
+      color: #1D1D1D;
+      border: 1px solid rgba(0, 0, 0, 0.08);
+      cursor: pointer;
+      .iconfont{
+        margin-right: 4px;
+        color: #686868;
+        font-size: 20px;
+      }
+      &:hover{
+        color: #fff;
+        background: #2ABED1;
+        border-color: #2ABED1;
+        i{
+          color: #fff;
+        }
+      }
     }
   }
   .customer-container{
     // display: none;
     position: fixed;
-     right: 84px;
+    right: 84px;
     bottom: 80px;
     max-height: 674px;
     min-height: 400px;