layout.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <template>
  2. <el-container>
  3. <el-aside :class="menuClass" width="">
  4. <el-menu :default-active="menuActiveIndex" :router="true" :collapse="isCollapse" :unique-opened="true">
  5. <div class="site-title">
  6. <h1>{{siteTitle}}</h1>
  7. </div>
  8. <div class="user-profile">
  9. <!--<img :src="userAvatar" alt="" class="profile-avatar img-circle">-->
  10. <img src="../../static/img/avatar/1.png" alt="" class="profile-avatar img-circle">
  11. <el-dropdown>
  12. <span class="el-dropdown-link">
  13. {{userName}} <i class="el-icon-caret-bottom el-icon--right"></i>
  14. </span>
  15. <el-dropdown-menu slot="dropdown">
  16. <el-dropdown-item icon="el-icon-user" @click.native="onGo('/user/index')">Personal Information</el-dropdown-item><!--个人资料-->
  17. <!--<el-dropdown-item icon="el-icon-message" @click.native="onGo('/message/list')">站内信</el-dropdown-item>-->
  18. <!-- <el-dropdown-item icon="el-icon-setting" @click.native="onGo('/config/base')">个人设置</el-dropdown-item>-->
  19. <el-dropdown-item icon="el-icon-switch-button" @click.native="onLogout">Log Out</el-dropdown-item><!--安全退出-->
  20. </el-dropdown-menu>
  21. </el-dropdown>
  22. </div>
  23. <template v-for="parent in menu">
  24. <el-submenu :index="'/'+parent.routePath" v-if="parent.child.length">
  25. <template slot="title">
  26. <i :class="parent.icon"></i>
  27. <span>{{parent.name}}</span>
  28. <span v-show="parent.routePath==='message'&&notifyShow" class="text-danger">new</span>
  29. </template>
  30. <el-menu-item-group title="">
  31. <el-menu-item :index="'/'+child.routePath" v-for="child in parent.child" :key="'/'+child.routePath">
  32. {{child.name}}
  33. </el-menu-item>
  34. </el-menu-item-group>
  35. </el-submenu>
  36. <el-menu-item :index="'/'+parent.routePath" v-else>
  37. <i :class="parent.icon"></i>
  38. <span>{{parent.name}}</span>
  39. </el-menu-item>
  40. </template>
  41. </el-menu>
  42. </el-aside>
  43. <el-container>
  44. <el-header>
  45. <ul class="al-left layout-menu-left">
  46. <li class="mobile-menu">
  47. <el-button type="text" @click="onMobileMenu"><i class="el-icon-s-fold"></i></el-button>
  48. </li>
  49. <li class="scale-menu">
  50. <el-button type="text" @click="onMenu"><i class="el-icon-s-fold"></i></el-button>
  51. </li>
  52. <li class="top-message button">
  53. <el-button type="text" @click="onMessage"><i class="el-icon-message"></i>
  54. <div class="notify" v-show="notifyShow"><span class="heartbit"></span><span class="point"></span></div>
  55. </el-button>
  56. <transition name="custom-classes-transition" enter-active-class="animated bounceInDown">
  57. <div class="top-message-card" v-if="messageShow" v-loading="messageLoading">
  58. <ul v-if="unreadMessage !== null">
  59. <li v-for="(item,index) in unreadMessage" :key="index" @click="toMessage(item.ID)">
  60. <h5>{{item.TITLE}}</h5>
  61. <span>{{tool.formatDate(item.CREATED_AT)}}</span>
  62. </li>
  63. </ul>
  64. </div>
  65. </transition>
  66. </li>
  67. </ul>
  68. <div style="text-align: right">
  69. <el-button type="text" @click.native="onLogout">Log Out</el-button><!--安全退出-->
  70. </div>
  71. </el-header>
  72. <div :class="'breadcrumb-box '+menuClass">
  73. <h4>{{contentTitle}}</h4>
  74. <div class="breadcrumb-content">
  75. <el-breadcrumb separator="/">
  76. <el-breadcrumb-item v-for="(item, index) in breadcrumb" :to="{ path: item.path }" :key="index">
  77. {{item.title}}
  78. </el-breadcrumb-item>
  79. </el-breadcrumb>
  80. </div>
  81. </div>
  82. <el-main>
  83. <router-view></router-view>
  84. </el-main>
  85. </el-container>
  86. </el-container>
  87. </template>
  88. <script>
  89. import {WEBSOCKET_HOST, CDN_IMG_URL} from '@/utils/config'
  90. import websocketHelper from '@/utils/websocketHelper';
  91. import userInfo from '@/utils/userInfo'
  92. import network from '@/utils/network'
  93. import tool from '@/utils/tool'
  94. import Waves from '@/static/plugins/waves/waves.js'
  95. import store from '@/utils/vuexStore'
  96. import baseInfo from '@/utils/baseInfo'
  97. import initRegion from '@/utils/region'
  98. export default {
  99. name: 'layout',
  100. beforeCreate () {
  101. let thisObj = this
  102. // 检测用户是否已经登录,如果已经登录则直接跳转到控制台页
  103. if (!userInfo.hasLogin()) {
  104. this.$router.push('/login')
  105. return
  106. }
  107. // 获取未读消息数量
  108. if (store.state.baseInfo.messageUnreadNum === null) {
  109. network.getUnreadMessage()
  110. }
  111. let baseInfo = userInfo.baseData()
  112. //链接websocket 服务器
  113. this.$webSocket.onOpen(thisObj, function(evt){
  114. thisObj.$webSocket.onSend(thisObj, JSON.stringify({
  115. cmd: websocketHelper.HAND_SHAKE,
  116. app: websocketHelper.WS_APP_BONUS,
  117. userId: baseInfo.ID
  118. }));
  119. });
  120. this.$webSocket.onMessage(thisObj, function(res){
  121. websocketHelper.onMessage(res,baseInfo);
  122. });
  123. // websocket连接
  124. /*let wsServer = WEBSOCKET_HOST
  125. let webSocket = new WebSocket(wsServer)
  126. store.state.socket.socketObj = webSocket
  127. webSocket.onopen = function (evt) {
  128. let userId = userInfo.userId()
  129. let sendData = {app: 'userPc', userId: userId}
  130. webSocket.send(JSON.stringify(sendData))
  131. }
  132. webSocket.onmessage = function (env) {
  133. let data = JSON.parse(env.data)
  134. if (data.handle === 'userPullMsg') {
  135. // vueObj.$message({
  136. // message: data.message,
  137. // type: data.success ? 'success' : 'error',
  138. // });
  139. // if(store.state.socket.onMessageCallback !== null){
  140. // store.state.socket.onMessageCallback();
  141. // }
  142. // 请求服务器拉取信息
  143. network.getData('message/pull').then(response => {
  144. // 请求服务器,获取未读站内信数量
  145. return network.getUnreadMessage()
  146. })
  147. }
  148. }*/
  149. // 获取地区信息
  150. initRegion(thisObj)
  151. },
  152. mounted () {
  153. let promise = network.getSiteInfo().then(response => {
  154. this.siteTitle = response.siteTitle
  155. })
  156. Waves.init()
  157. Waves.attach('.waves-btn')
  158. },
  159. data () {
  160. return {
  161. isCollapse: false,
  162. menuActiveIndex: this.$route.meta.highLight || this.$route.path,
  163. mainTitle: this.$route.meta.title,
  164. messageShow: false,
  165. profileShow: false,
  166. userNameShow: true,
  167. menuClass: '',
  168. userName: userInfo.userName(),
  169. userAvatar: userInfo.baseData().AVATAR,
  170. messageLoading: true,
  171. unreadMessage: null,
  172. tool: tool,
  173. siteTitle: '',
  174. }
  175. },
  176. computed: {
  177. menu: function () {
  178. return baseInfo.menu()
  179. },
  180. contentTitle: function () {
  181. return this.$route.meta.title
  182. },
  183. breadcrumb: function () {
  184. let breadcrumbArr = []
  185. for (let i in this.$route.meta.breadcrumb) {
  186. breadcrumbArr.push(this.$route.meta.breadcrumb[i])
  187. }
  188. breadcrumbArr.push({title: this.$route.meta.title, path: ''})
  189. return breadcrumbArr
  190. },
  191. notifyShow: function () {
  192. if (store.state.baseInfo.messageUnreadNum > 0) {
  193. return true
  194. } else {
  195. return false
  196. }
  197. }
  198. },
  199. methods: {
  200. onMenu () {
  201. if (this.isCollapse) {
  202. this.isCollapse = false
  203. document.getElementsByTagName('body')[0].className = ''
  204. } else {
  205. this.isCollapse = true
  206. document.getElementsByTagName('body')[0].className = 'content-wrapper'
  207. }
  208. },
  209. onMobileMenu () {
  210. if (this.menuClass === 'show-menu') {
  211. this.menuClass = ''
  212. } else {
  213. this.menuClass = 'show-menu'
  214. }
  215. },
  216. onMessage () {
  217. if (store.state.baseInfo.messageUnreadNum > 0) {
  218. this.messageShow = !this.messageShow
  219. network.getData(`message/unread-text`).then(response => {
  220. this.unreadMessage = response
  221. this.messageLoading = false
  222. })
  223. } else {
  224. this.$message({
  225. message: 'No Unread Message',//暂无未读消息
  226. type: 'warning'
  227. })
  228. }
  229. },
  230. onProfile () {
  231. this.profileShow = !this.profileShow
  232. },
  233. onGo(url) {
  234. this.$router.push(url)
  235. },
  236. onLogout () {
  237. userInfo.clear()
  238. this.$router.push('/login')
  239. },
  240. onCloseProfile () {
  241. this.profileShow = false
  242. },
  243. toMessage (id) {
  244. this.$router.push(`/message/detail/${id}`)
  245. this.messageShow = !this.messageShow
  246. network.getData(`message/unread-text`).then(response => {
  247. this.unreadMessage = response
  248. this.messageLoading = false
  249. })
  250. }
  251. }
  252. }
  253. </script>
  254. <style>
  255. @import '../../static/css/animate.css';
  256. @import '../../static/plugins/waves/waves.css';
  257. @import '../../static/css/style.css';
  258. .el-menu-item-group__title{display: none;}
  259. .top-message {
  260. position: relative
  261. }
  262. .top-message .notify {
  263. position: relative;
  264. margin-top: -8px;
  265. }
  266. .top-message .notify .heartbit {
  267. position: absolute;
  268. top: -24px;
  269. right: -20px;
  270. height: 25px;
  271. width: 25px;
  272. z-index: 10;
  273. border: 5px solid #f75b36;
  274. border-radius: 70px;
  275. animation: heartbit 1s ease-out;
  276. animation-iteration-count: infinite;
  277. }
  278. .top-message .notify .point {
  279. width: 6px;
  280. height: 6px;
  281. -webkit-border-radius: 30px;
  282. -moz-border-radius: 30px;
  283. border-radius: 30px;
  284. background-color: #f75b36;
  285. position: absolute;
  286. right: -5px;
  287. top: -9px;
  288. }
  289. @keyframes heartbit {
  290. 0% {
  291. transform: scale(0);
  292. opacity: 0
  293. }
  294. 25% {
  295. transform: scale(.1);
  296. opacity: .1
  297. }
  298. 50% {
  299. transform: scale(.5);
  300. opacity: .3
  301. }
  302. 75% {
  303. transform: scale(.65);
  304. opacity: .5
  305. }
  306. 100% {
  307. transform: scale(.8);
  308. opacity: 0
  309. }
  310. }
  311. </style>