Header.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. <template>
  2. <div class="header" :class="[collapse ? 'collapse' : 'expand']">
  3. <div class="el-fl-left"><v-tags></v-tags></div>
  4. <div class="header-right">
  5. <div class="header-user-con">
  6. <div class="formulation" @click="formulationToPage" v-if="permissionFiltering">
  7. <img src="@assets/img/formulation/icon_diygzt@2x.png" alt="" />
  8. 工作台自拟定 <span class="border"></span>
  9. </div>
  10. <div>欢迎你,{{ cruUserInfo.username }}</div>
  11. <!-- 用户头像 -->
  12. <div class="user-avator" @click="editUserInfo">
  13. <el-tooltip v-show="!cruUserInfo.photo" placement="bottom" content="编辑用户信息">
  14. <img src="@assets/img/formulation/icon_avatar@2x.png" alt="" />
  15. </el-tooltip>
  16. <img v-show="cruUserInfo.photo" :src="envConfig.baseImgApi + cruUserInfo.photo" style="object-fit: cover" />
  17. </div>
  18. <div class="message">
  19. <span class="main" @click="goMessage('unread')">
  20. <img src="@assets/img/btn_news.png" alt="" />
  21. <span class="iconfont point" v-if="messageNumber"></span>
  22. </span>
  23. <div class="msg-content" v-if="messageList && messageList.length">
  24. <p>消息通知</p>
  25. <ul>
  26. <li v-for="(items, index) in messageList" :key="index" @click="toUrl(items.typeId)" style="cursor: pointer">
  27. <img :src="imgList[items.typeId]" style="width: 30px; height: 30px" />
  28. <div>
  29. <span class="cont">【{{ items.shortName }}】{{ items.messageContent }}</span>
  30. <span class="time">{{ items.dateCreate }}</span>
  31. </div>
  32. </li>
  33. </ul>
  34. <el-button type="text" class="more" @click="goMessage('more')">查看更多</el-button>
  35. </div>
  36. <div class="msg-content" v-else>
  37. <p>消息通知</p>
  38. <ul>
  39. <li style="text-align: center; display: block; padding: 0 rem(20); line-height: rem(60)">暂无消息</li>
  40. </ul>
  41. <el-button type="text" class="more" disabled>查看更多</el-button>
  42. </div>
  43. </div>
  44. <span class="border"></span>
  45. <div class="logout" @click="logOut">
  46. <el-tooltip placement="bottom" content="退出">
  47. <i class="zoniot_font zoniot-icon-tuichu"></i>
  48. </el-tooltip>
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. </template>
  54. <script>
  55. import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
  56. import envConfig from '@/config';
  57. import vTags from './Tags.vue';
  58. export default {
  59. data() {
  60. return {
  61. name: '',
  62. envConfig: envConfig,
  63. imgList: {
  64. 1: require('@/assets/img/icon_msg1.png'),
  65. 2: require('@/assets/img/icon_msg7.png'),
  66. 10: require('@/assets/img/icon_msg9.png'),
  67. 11: require('@/assets/img/icon_msg9.png'),
  68. 13: require('@/assets/img/icon_msg9.png')
  69. }
  70. };
  71. },
  72. components: {
  73. vTags
  74. },
  75. computed: {
  76. cruUserInfo() {
  77. return this.$store.getters['getCruUserInfo'];
  78. },
  79. collapse() {
  80. return this.$store.getters['getCollapse'];
  81. },
  82. permissionFiltering() {
  83. let arr = this.$store.getters['getMenuList'] || [];
  84. if (arr.length !== 0) {
  85. return this.filterFuntion(false, arr);
  86. } else {
  87. return false;
  88. }
  89. },
  90. ...mapState(['messageNumber']),
  91. ...mapState(['messageList'])
  92. },
  93. methods: {
  94. filterFuntion(status, arr) {
  95. arr.some((item, index) => {
  96. if (item.children == null && item.name == '工作台' && item.linkPath == 'newWorkBench/index') {
  97. status = true;
  98. return false;
  99. }
  100. });
  101. return status;
  102. },
  103. toUrl(type) {
  104. this.$router.push({
  105. path: '/msg'
  106. });
  107. },
  108. formulationToPage() {
  109. this.$router.push({
  110. path: '/editWorkbench'
  111. });
  112. },
  113. // 退出登录
  114. logOut() {
  115. var access_token = localStorage.getItem('SC_token');
  116. this.$http.postForm('/user-auth/user/logout', { access_token: access_token }).then(({ status, data, msg }) => {
  117. if (0 === status) {
  118. this.$message({
  119. type: 'success',
  120. message: '您已退出登录'
  121. });
  122. localStorage.removeItem('SC_token');
  123. sessionStorage.removeItem('SC_listMuen');
  124. this.$store.commit('setloginInfo', '');
  125. this.$store.dispatch('tags', []);
  126. sessionStorage.removeItem('tabs');
  127. location.href = this.envConfig.loginUrl;
  128. } else {
  129. this.$message.error(msg);
  130. }
  131. });
  132. },
  133. getUserInfo(resolve) {
  134. this.$http.postForm('/sc-user-center/user/findLoginUserById').then(({ status, data, msg }) => {
  135. if (status === 0) {
  136. this.$store.commit('setcCruUserInfo', data);
  137. } else {
  138. this.$message.error('获取用户信息失败');
  139. }
  140. resolve && resolve(true);
  141. });
  142. },
  143. editUserInfo() {
  144. new Promise((resolve) => {
  145. this.$store.dispatch('addPopup', {
  146. url: '/system/users/popups/edituser.vue',
  147. width: '500px',
  148. height: '500px',
  149. props: {
  150. data: JSON.parse(JSON.stringify(this.cruUserInfo)),
  151. callback: resolve
  152. },
  153. title: '编辑用户信息'
  154. });
  155. }).then(() => {
  156. this.getUserInfo();
  157. });
  158. },
  159. goMessage(msg) {
  160. let messageStatus = 2; //全部
  161. if (msg == 'unread') {
  162. messageStatus = 0; //未读
  163. }
  164. this.$store.commit('setmessageStatus', messageStatus);
  165. this.$router.push({
  166. path: '/msg'
  167. });
  168. },
  169. //获取最新消息列表
  170. getMessageList() {
  171. this.$http.postForm('/sc-message/message/queryLastMessage', { num: '5' }).then(({ status, data, msg }) => {
  172. if (status === 0) {
  173. this.$store.commit('setmessageList', data);
  174. }
  175. });
  176. },
  177. //查询未读消息数量
  178. getUnreadNumber() {
  179. this.$http.postForm('/sc-message/message/queryUnreadMessageStatic').then(({ status, data, msg }) => {
  180. if (status === 0) {
  181. data.map((item, index) => {
  182. if (item.cn) {
  183. this.$store.commit('setmessageNumber', true);
  184. }
  185. });
  186. }
  187. });
  188. },
  189. //初始化websoket
  190. initWebSocket(id) {
  191. if ('WebSocket' in window) {
  192. var serviceIp = this.envConfig.websoketUrl;
  193. this.websocket = new WebSocket('ws://' + serviceIp + '/sc-message/webSocket/' + id);
  194. } else {
  195. console.log('当前浏览器 Not support websocket');
  196. }
  197. let that = this;
  198. this.interval = window.setInterval(function () {
  199. //每隔30秒钟发送一次心跳,避免websocket连接因超时而自动断开
  200. if (that.websocket != null) {
  201. // that.websocket.send('HeartBeat');
  202. // console.log('发送心跳包:HeartBeat');
  203. }
  204. }, 30000);
  205. //连接发生错误的回调方法
  206. this.websocket.onerror = function (ev) {
  207. console.log('WebSocket连接发生错误');
  208. };
  209. //连接成功建立的回调方法
  210. this.websocket.onopen = function (ev) {
  211. console.log('WebSocket连接成功');
  212. // this.send('addsocket');
  213. };
  214. //接收到消息的回调方法
  215. this.websocket.onmessage = function (event) {
  216. try {
  217. let msg = JSON.parse(event.data);
  218. // let i = msg.typeId - 1;
  219. let i = msg.typeId;
  220. if (msg.userId) {
  221. that.$notify({
  222. dangerouslyUseHTMLString: true,
  223. showClose: true,
  224. customClass: 'notice_icon',
  225. offset: 50,
  226. duration: 3000,
  227. message:
  228. "<div class='notice'><img src=" +
  229. that.imgList[i] +
  230. " class='img'/><div class='notice-content'><span class='title'>新消息通知</span><span class='nowrap'>" +
  231. '【' +
  232. msg.type +
  233. '】' +
  234. msg.content +
  235. '</span></div></div>'
  236. });
  237. that.getMessageList();
  238. that.getUnreadNumber();
  239. }
  240. } catch (e) {}
  241. };
  242. //连接关闭的回调方法
  243. this.websocket.onclose = function (ev) {
  244. console.log('WebSocket连接关闭');
  245. this.websocket = null;
  246. };
  247. },
  248. send(message) {
  249. if (this.websocket && this.websocket != null) {
  250. // this.websocket.send(message);
  251. console.log('发送的消息:' + message);
  252. }
  253. },
  254. //关闭WebSocket连接
  255. closeWebSocket() {
  256. if (this.websocket != null) {
  257. this.websocket.close();
  258. }
  259. if (this.interval) {
  260. window.clearInterval(this.interval);
  261. }
  262. }
  263. },
  264. mounted() {
  265. let vm = this;
  266. window.onbeforeunload = function () {
  267. vm.closeWebSocket();
  268. };
  269. },
  270. destoryed() {
  271. this.closeWebSocket();
  272. },
  273. created() {
  274. new Promise((resolve) => {
  275. this.getUserInfo(resolve);
  276. }).then((_) => {
  277. let id = this.$store.state.cruUserInfo.id;
  278. this.initWebSocket(id);
  279. this.getMessageList();
  280. this.getUnreadNumber();
  281. });
  282. }
  283. };
  284. </script>
  285. <style lang='scss' scoped>
  286. @import '@assets/css/public-style.scss';
  287. .border {
  288. width: 1px;
  289. height: rem(10);
  290. background: #ffffffa5;
  291. }
  292. .header {
  293. height: rem(46);
  294. font-size: rem(14);
  295. color: #fff;
  296. background: #2c354a;
  297. display: flex;
  298. align-items: center;
  299. justify-content: space-between;
  300. &.expand::before {
  301. content: '';
  302. display: inline-block;
  303. width: rem(220);
  304. height: rem(46);
  305. background: #2c354a;
  306. position: absolute;
  307. left: 0;
  308. }
  309. &.collapse::before {
  310. content: '';
  311. display: inline-block;
  312. width: rem(85);
  313. height: rem(46);
  314. background: #2c354a;
  315. position: absolute;
  316. left: 0;
  317. }
  318. }
  319. .header-right {
  320. padding-right: rem(20);
  321. color: rgba(255, 255, 255, 0.6);
  322. display: flex;
  323. .formulation {
  324. height: rem(46);
  325. line-height: rem(46);
  326. cursor: pointer;
  327. img {
  328. width: rem(20);
  329. height: rem(20);
  330. vertical-align: middle;
  331. margin-right: rem(10);
  332. }
  333. .border {
  334. margin: 0 rem(20);
  335. display: inline-block;
  336. }
  337. }
  338. .name-txt {
  339. font-size: rem(12);
  340. font-family: PingFangSC-Regular, PingFang SC;
  341. font-weight: 400;
  342. color: #ffffff;
  343. }
  344. }
  345. .header-user-con {
  346. display: flex;
  347. align-items: center;
  348. }
  349. .logout {
  350. margin-left: rem(20);
  351. i {
  352. color: white;
  353. font-size: rem(20);
  354. }
  355. }
  356. .iconfont {
  357. font-size: rem(20);
  358. color: rgba(255, 255, 255, 0.6);
  359. &:hover {
  360. color: rgba(255, 255, 255, 1);
  361. }
  362. }
  363. .user-avator {
  364. margin-left: rem(10);
  365. margin-right: rem(20);
  366. }
  367. .user-avator img {
  368. display: block;
  369. width: rem(20);
  370. height: rem(20);
  371. cursor: pointer;
  372. }
  373. .message {
  374. margin-right: rem(20);
  375. color: #000000;
  376. cursor: pointer;
  377. &:hover {
  378. .msg-content {
  379. display: block;
  380. background: #ffffff;
  381. box-shadow: 0px rem(5) rem(20) 0px rgba(144, 144, 144, 0.4);
  382. border-radius: rem(6);
  383. z-index: 200;
  384. }
  385. }
  386. .main {
  387. height: rem(46);
  388. line-height: rem(46);
  389. position: relative;
  390. img {
  391. width: rem(20);
  392. height: rem(20);
  393. vertical-align: text-bottom;
  394. }
  395. .point {
  396. position: absolute;
  397. top: rem(-4);
  398. right: -1px;
  399. width: rem(4);
  400. height: rem(4);
  401. background: #fe7271;
  402. border-radius: 50%;
  403. display: block;
  404. }
  405. }
  406. .msg-content {
  407. position: absolute;
  408. width: rem(380);
  409. background: #ffffff;
  410. z-index: 20;
  411. right: rem(20);
  412. top: rem(40);
  413. transition: all 0.3s;
  414. display: none;
  415. p {
  416. height: rem(40);
  417. line-height: rem(40);
  418. padding-left: rem(20);
  419. color: #212226;
  420. }
  421. li {
  422. display: flex;
  423. align-items: center;
  424. height: rem(60);
  425. padding-left: rem(20);
  426. border-top: 1px solid #f6f6f6;
  427. font-size: rem(12);
  428. cursor: auto;
  429. span {
  430. width: rem(300);
  431. overflow: hidden; //超出的文本隐藏
  432. text-overflow: ellipsis; //溢出用省略号显示
  433. white-space: nowrap; //溢出不换行
  434. display: block;
  435. line-height: rem(20);
  436. padding-left: 1rem (5);
  437. }
  438. .cont {
  439. color: #424656;
  440. text-indent: -0.4em;
  441. }
  442. .time {
  443. color: #7d7f87;
  444. }
  445. }
  446. .more {
  447. width: 100%;
  448. }
  449. }
  450. }
  451. </style>