index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <div class="navbar-group">
  3. <div class="logo">
  4. <img :src="logo" alt="logo">
  5. </div>
  6. <div class="nav-group">
  7. <div
  8. class="nav-item"
  9. :class="nav.class"
  10. v-for="(nav, index) in navs"
  11. :key="index"
  12. @click="onSelectNav(nav)"
  13. >
  14. <template v-if="nav.plugin">
  15. <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-popover:[nav.plugin]></navbar-item>
  16. </template>
  17. <navbar-item :badge="nav.badge" :svg="nav.svg" :nav="nav" v-else></navbar-item>
  18. </div>
  19. <el-popover
  20. popper-class="nav-popover"
  21. ref="navInfo"
  22. placement="bottom"
  23. trigger="hover"
  24. :visible-arrow="false"
  25. >
  26. <div class="nav-user-info-group">
  27. <navbar-item :nav="{ icon: userInfo.avatar }" mode="vertical">
  28. <div class="info-group">
  29. <span v-if="userInfo.name">{{userInfo.name}}</span>
  30. <span v-if="userInfo.phone">{{userInfo.phone}}</span>
  31. </div>
  32. </navbar-item>
  33. <button @click="onClickOut">退出登录</button>
  34. </div>
  35. </el-popover>
  36. <el-popover
  37. popper-class="nav-popover"
  38. ref="navCustomer"
  39. placement="bottom"
  40. trigger="hover"
  41. :visible-arrow="false"
  42. >
  43. <div class="nav-custom-info-group">
  44. <div class="info-item" v-if="hasExclusiveCustomer">
  45. <div class="after-tag-box recommend-tag">推荐</div>
  46. <navbar-item :nav="{ label: '专属客服:' + exclusiveCustomerInfo.name, icon: 'icon-weixin_line' }"></navbar-item>
  47. <navbar-item
  48. class="qrcode-group"
  49. :nav="{
  50. label: '微信扫一扫',
  51. icon: exclusiveCustomerInfo.qrcode
  52. }"
  53. mode="vertical"
  54. >
  55. </navbar-item>
  56. </div>
  57. <div class="info-item">
  58. <navbar-item :nav="{ label: '在线咨询', icon: 'icon-kefu_xian' }" :svg="true"></navbar-item>
  59. </div>
  60. <div class="info-item">
  61. <navbar-item :nav="{ label: '客服热线:400-108-6670', icon: 'icon-telphone_line' }"></navbar-item>
  62. </div>
  63. </div>
  64. </el-popover>
  65. <el-popover
  66. popper-class="nav-popover"
  67. ref="navMessage"
  68. placement="bottom"
  69. trigger="hover"
  70. :visible-arrow="false"
  71. >
  72. <div class="nav-message-group">
  73. <div class="message-header">
  74. <div class="title">
  75. 消息中心 <span>(<span class="highlight-text">{{messageCount}}</span> 条未读)</span>
  76. </div>
  77. <JyIcon @click="closeMessagePopver" name="close"></JyIcon>
  78. </div>
  79. <div class="message-group" v-if="messageList.length">
  80. <div
  81. v-for="(message, index) in messageList"
  82. :key="index"
  83. class="message-item"
  84. @click="onClickMessage(message)"
  85. >
  86. <el-badge :isDot="!message.read" class="message-icon">
  87. <img :src="message.icon" alt="icon">
  88. </el-badge>
  89. <div class="message-content">
  90. <div class="message-content--header">
  91. <div class="message-content--title ellipsis">
  92. {{message.title}}
  93. </div>
  94. <div class="message-content--time">
  95. {{message.time}}
  96. </div>
  97. </div>
  98. <div class="message-content--content">
  99. {{message.content}}
  100. </div>
  101. </div>
  102. </div>
  103. </div>
  104. <empty-tip v-else tip="暂未接收到信息"></empty-tip>
  105. <button @click="onClickMessageAll">查看全部</button>
  106. </div>
  107. </el-popover>
  108. </div>
  109. </div>
  110. </template>
  111. <script>
  112. import NavbarItem from './components/item'
  113. import { mapActions, mapGetters, mapState } from 'vuex'
  114. import EmptyTip from '../Empty'
  115. import { completeURLPrefix } from '../../micro-frame'
  116. export default {
  117. name: 'header-navbar',
  118. components: {
  119. [NavbarItem.name]: NavbarItem,
  120. [EmptyTip.name]: EmptyTip
  121. },
  122. created () {
  123. this.getPower()
  124. this.getUserSimpleInfo().then(() => {
  125. const userInfo = this.navs.find(v => v.plugin === 'navInfo')
  126. userInfo.label = this.userInfo.name || this.userInfo.phone
  127. userInfo.icon = this.userInfo.avatar
  128. })
  129. this.getMessageCount().then(() => {
  130. this.navs.find(v => v.label === '消息中心').badge = this.messageCount
  131. })
  132. this.getMessages()
  133. },
  134. data () {
  135. return {
  136. home: process.env.VUE_APP_BASE_SITE,
  137. logo: 'https://cdn-ali.jianyu360.com/images/swordfish/sf_01_new.png',
  138. navs: [
  139. {
  140. label: '前往官网',
  141. icon: 'icon-houtui'
  142. },
  143. {
  144. label: '消息中心',
  145. icon: 'icon-a-Property1gongzuozhuomianProperty2xiaoxizhongxinProperty3grey',
  146. badge: 0,
  147. plugin: 'navMessage'
  148. },
  149. {
  150. label: '客服',
  151. icon: 'icon-kefu_xian',
  152. svg: true,
  153. plugin: 'navCustomer'
  154. },
  155. {
  156. label: '',
  157. icon: 'https://www.jianyu360.cn/common-module/public/image/auto.png',
  158. plugin: 'navInfo',
  159. class: 'nav-user-info'
  160. }
  161. ]
  162. }
  163. },
  164. computed: {
  165. ...mapState('work-bench/navbar', [
  166. 'messageCount'
  167. ]),
  168. ...mapGetters('work-bench/user', [
  169. 'hasExclusiveCustomer',
  170. 'exclusiveCustomerInfo',
  171. 'userInfo'
  172. ]),
  173. ...mapGetters('work-bench/navbar', [
  174. 'messageList'
  175. ]),
  176. },
  177. methods: {
  178. ...mapActions('work-bench', [
  179. 'getPower',
  180. 'getUserSimpleInfo',
  181. 'setSignOut',
  182. 'getMessageCount',
  183. 'getMessages',
  184. 'setClickMessage',
  185. 'setReadMessage'
  186. ]),
  187. onClickOut () {
  188. this.setSignOut()
  189. document.cookie = 'userid_secure=;expires=-1;path=/'
  190. this.goSiteHome()
  191. },
  192. onSelectNav (nav) {
  193. console.log(nav, 'xxx')
  194. switch (nav.label) {
  195. case '消息中心': {
  196. this.$router.push({
  197. name: 'page',
  198. query: {
  199. link: completeURLPrefix('/swordfish/frontPage/messageCenter/sess/index')
  200. }
  201. })
  202. break
  203. }
  204. case '前往官网': {
  205. this.goSiteHome()
  206. break
  207. }
  208. }
  209. },
  210. goSiteHome () {
  211. location.href = completeURLPrefix(this.home)
  212. },
  213. closeMessagePopver () {
  214. this.$refs.navMessage.doClose()
  215. },
  216. onClickMessage (message) {
  217. this.setClickMessage({
  218. id: message.origin.msgLogId
  219. })
  220. if (message.read) {
  221. if (message.link) {
  222. location.href = message.link
  223. }
  224. } else {
  225. this.setReadMessage({
  226. id: message.origin.id,
  227. type: message.origin.msg_type
  228. }).then(() => {
  229. if (message.link) {
  230. location.href = message.link
  231. } else {
  232. this.getMessageCount().then(() => {
  233. this.navs.find(v => v.label === '消息中心').badge = this.messageCount
  234. })
  235. this.getMessages()
  236. }
  237. })
  238. }
  239. },
  240. onClickMessageAll () {
  241. this.closeMessagePopver()
  242. this.onSelectNav({
  243. label: '消息中心'
  244. })
  245. }
  246. }
  247. }
  248. </script>
  249. <style lang="scss">
  250. .flex-horizontal {
  251. display: flex;
  252. flex-direction: row;
  253. align-items: center;
  254. }
  255. .flex-vertical {
  256. display: flex;
  257. flex-direction: column;
  258. align-items: center;
  259. justify-content: center;
  260. }
  261. .nav-popover {
  262. &.el-popper[x-placement^=bottom] {
  263. margin-top: 20px;
  264. }
  265. padding: 0;
  266. border: none;
  267. background: #FFFFFF;
  268. box-shadow: 0px 5px 5px -3px rgba(0,0,0,0.1000), 0px 8px 10px 1px rgba(0,0,0,0.0600), 0px 3px 14px 2px rgba(0,0,0,0.0500);
  269. border-radius: 8px;
  270. overflow: hidden;
  271. }
  272. .nav-custom-info-group {
  273. min-width: 229px;
  274. .info-item {
  275. position: relative;
  276. padding: 12px 16px;
  277. .after-tag-box {
  278. position: absolute;
  279. right: 0;
  280. top: 16px;
  281. }
  282. .qrcode-group {
  283. padding-bottom: 4px;
  284. .img-icon {
  285. width: 90px;
  286. height: 90px;
  287. border-radius: unset;
  288. margin-right: 0;
  289. }
  290. span {
  291. margin-left: 0;
  292. }
  293. }
  294. span {
  295. margin-left: 4px;
  296. font-size: 14px;
  297. color: #686868;
  298. line-height: 22px;
  299. }
  300. & + .info-item {
  301. border-top: 1px solid #ECECEC;
  302. }
  303. }
  304. }
  305. .nav-user-info-group {
  306. width: 150px;
  307. padding-top: 18px;
  308. .info-group {
  309. width: 100%;
  310. @extend .flex-vertical;
  311. padding: 0 16px 8px 18px;
  312. box-sizing: border-box;
  313. span {
  314. width: 100%;
  315. text-align: center;
  316. display: inline-block;
  317. overflow:hidden;
  318. text-overflow:ellipsis;
  319. white-space:nowrap;
  320. }
  321. }
  322. button {
  323. width: 100%;
  324. height: 34px;
  325. background: #F5F6F7;
  326. text-align: center;
  327. font-size: 12px;
  328. font-weight: 400;
  329. color: #686868;
  330. cursor: pointer;
  331. }
  332. }
  333. .nav-message-group {
  334. width: 400px;
  335. .message-header {
  336. @extend .flex-horizontal;
  337. padding: 16px 24px;
  338. font-size: 16px;
  339. color: #1D1D1D;
  340. line-height: 24px;
  341. box-shadow: inset 0px -1px 0px 1px rgba(0,0,0,0.0500);
  342. .title {
  343. flex: 1;
  344. }
  345. span {
  346. font-size: 14px;
  347. color: #686868;
  348. &.highlight-text {
  349. color: #2ABED1;
  350. }
  351. }
  352. .icon-close {
  353. font-size: 20px;
  354. cursor: pointer;
  355. color: #AAAAAA;
  356. &:hover {
  357. color: #2cb7ca;
  358. }
  359. }
  360. }
  361. .message-group {
  362. flex: 1;
  363. max-height: 263px;
  364. overflow-y: scroll;
  365. }
  366. .message-item {
  367. @extend .flex-horizontal;
  368. width: 100%;
  369. padding: 12px 24px;
  370. box-sizing: border-box;
  371. border-bottom: 1px solid #ECECEC;
  372. cursor: pointer;
  373. &:last-child {
  374. border-bottom: unset;
  375. }
  376. &:hover {
  377. background-color: #f5f6f7;
  378. }
  379. }
  380. .message-icon {
  381. flex-shrink: 0;
  382. width: 32px;
  383. height: 32px;
  384. border-radius: 50%;
  385. img {
  386. border-radius: 50%;
  387. overflow: hidden;
  388. }
  389. border: 1px solid rgba(0,0,0,0.0500);
  390. margin-right: 12px;
  391. .el-badge__content.is-fixed.is-dot {
  392. right: 8px;
  393. top: 2px;
  394. }
  395. }
  396. .message-content {
  397. display: flex;
  398. flex: 1;
  399. flex-wrap: wrap;
  400. flex-direction: column;
  401. &--header {
  402. @extend .flex-horizontal;
  403. flex: 1;
  404. justify-content: space-between;
  405. }
  406. &--content {
  407. margin-top: 4px;
  408. font-size: 13px;
  409. color: #686868;
  410. line-height: 20px;
  411. }
  412. &--title {
  413. font-size: 14px;
  414. color: #1D1D1D;
  415. line-height: 22px;
  416. }
  417. &--time {
  418. font-size: 12px;
  419. color: #999999;
  420. line-height: 18px;
  421. }
  422. }
  423. button {
  424. background-color: transparent;
  425. border-top: 1px solid #ECECEC;
  426. width: 100%;
  427. font-size: 16px;
  428. color: #1D1D1D;
  429. line-height: 56px;
  430. cursor: pointer;
  431. &:hover {
  432. color: #2ABED1FF;
  433. }
  434. }
  435. }
  436. .recommend-tag {
  437. position: relative;
  438. @extend .flex-horizontal;
  439. display: inline-flex;
  440. height: 20px;
  441. padding-left: 16px;
  442. padding-right: 8px;
  443. background: linear-gradient(136deg, #FF9F40 0%, #FF3A20 100%);
  444. font-size: 12px;
  445. font-weight: 400;
  446. color: #FFFFFF;
  447. &::before {
  448. content: "";
  449. position: absolute;
  450. top: 3px;
  451. left: -8px;
  452. background: #fff;
  453. width: 14px;
  454. height: 14px;
  455. transform: rotate(45deg);
  456. border-radius: 2px;
  457. }
  458. }
  459. </style>
  460. <style scoped lang="scss">
  461. .flex-horizontal {
  462. display: flex;
  463. flex-direction: row;
  464. align-items: center;
  465. }
  466. .flex-vertical {
  467. display: flex;
  468. flex-direction: column;
  469. align-items: center;
  470. justify-content: center;
  471. }
  472. .navbar-group {
  473. position: relative;
  474. z-index: 2;
  475. @extend .flex-horizontal;
  476. justify-content: space-between;
  477. padding: 16px 36px;
  478. box-sizing: border-box;
  479. background-color: #ffffff;
  480. box-shadow: 0px 2px 8px -1px rgba(0,0,0,0.0800);
  481. .nav-user-info {
  482. ::v-deep .navbar-item--label {
  483. max-width: 118px;
  484. overflow:hidden;
  485. text-overflow:ellipsis;
  486. white-space:nowrap;
  487. }
  488. }
  489. .logo {
  490. display: inline-block;
  491. width: auto;
  492. height: 32px;
  493. img {
  494. height: 100%;
  495. }
  496. }
  497. .nav-group {
  498. @extend .flex-horizontal;
  499. font-size: 16px;
  500. font-weight: 400;
  501. color: #1D1D1D;
  502. line-height: 24px;
  503. .nav-item {
  504. height: 32px;
  505. }
  506. .nav-item + .nav-item {
  507. margin-left: 48px;
  508. }
  509. }
  510. }
  511. </style>