Head.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. <template>
  2. <div class="head-wrapper">
  3. <div class="head-logo">
  4. <svg-icon icon-class="zhihui-logo" @click="topHome()" />
  5. </div>
  6. <div
  7. v-for="item in headList"
  8. :key="item.path"
  9. class="nav-tag"
  10. :class="{ 'active-nav-tag': activeNavTag === item.name }"
  11. @click="changeNavTag(item)"
  12. >
  13. <div v-if="item.icon" class="icon">
  14. <div
  15. v-show="notice && item.name.search(/个人工作台/) >= 0"
  16. class="if-notice"
  17. />
  18. <svg-icon :icon-class="item.icon" :style="{width: item.name === '质量月报' ? '31px' : '100%', height: item.name === '质量月报' ? '25px' : '100%'}" />
  19. </div>
  20. <div class="name">{{ item.name }}</div>
  21. </div>
  22. <HeaderMenu />
  23. <el-tooltip
  24. class="item"
  25. effect="dark"
  26. content="用户指导手册"
  27. placement="right"
  28. >
  29. <el-link
  30. class="user-tip"
  31. href="https://base3.xiaojukeji.com/docs/zhihui/"
  32. target="_blank"
  33. >
  34. <svg-icon style="width: 24px; height: 24px" icon-class="question" />
  35. </el-link>
  36. </el-tooltip>
  37. <div v-if="userInfo" class="user-info">
  38. <a-popover placement="rightBottom" overlay-class-name="head-popover">
  39. <template #content>
  40. <div class="user-admin-one">
  41. <div class="title line">
  42. <svg-icon icon-class="setting" class="icon" />
  43. <span class="label">设置</span>
  44. </div>
  45. <div class="item mb16">
  46. <div class="label line">
  47. <el-switch
  48. :value="navTagType === 1"
  49. :size="size"
  50. class="mr10"
  51. @change="setNavTagType(navTagType === 2 ? 1 : 2)"
  52. />
  53. <span class="label-text">左侧导航</span>
  54. <el-tooltip
  55. effect="dark"
  56. content="可设置为“左侧导航”或“顶部导航”"
  57. placement="top-start"
  58. >
  59. <i class="el-icon-info" style="vertical-align: text-bottom" />
  60. </el-tooltip>
  61. </div>
  62. <div class="label line">
  63. <el-switch
  64. :value="openPageHandle === 'blank'"
  65. :size="size"
  66. class="mr10"
  67. @change="
  68. setOpenPageHandle(
  69. openPageHandle === 'blank' ? 'self' : 'blank'
  70. )
  71. "
  72. />
  73. <span class="label-text">详情页新标签页打开</span>
  74. <el-tooltip
  75. effect="dark"
  76. content="可设置详情页在“新标签页打开“,或”当前标签页“打开。"
  77. placement="top-start"
  78. >
  79. <i class="el-icon-info" style="vertical-align: text-bottom" />
  80. </el-tooltip>
  81. </div>
  82. </div>
  83. <div class="title line clickText" @click="administratorsJump()">
  84. <span v-if="memberCheck">
  85. <svg-icon icon-class="admin" class="icon" />
  86. <span class="label">管理员</span>
  87. </span>
  88. </div>
  89. <div class="item">
  90. <div class="label fontSize14">
  91. {{ userInfo.name }} {{ userInfo.idap }}
  92. </div>
  93. <div class="label">
  94. <span class="outLogin" @click="layout()">
  95. <i
  96. class="el-icon-switch-button icon"
  97. style="margin-right: 4px"
  98. />
  99. <span class="label">退出</span>
  100. </span>
  101. </div>
  102. </div>
  103. </div>
  104. </template>
  105. <img :src="userInfo.phoneUrl">
  106. </a-popover>
  107. </div>
  108. </div>
  109. </template>
  110. <script>
  111. import { mapGetters } from 'vuex'
  112. import routes from '@/router/newRouter'
  113. import HeaderMenu from './components/menu'
  114. import websocket from '@/views/workbench/mixins/websocket'
  115. import { memberGetLoginInMemberInfoByLdap } from '@/api/projectIndex'
  116. import { logoutUrl, envUrl } from '@/apiConfig/requestIP.js'
  117. import { verifyIsAdmin } from '@/api/configure.js'
  118. export default {
  119. components: {
  120. HeaderMenu
  121. },
  122. mixins: [websocket],
  123. data() {
  124. return {
  125. size: 'small',
  126. headList: routes.filter((item) => item.name !== '业务线'),
  127. userInfo: null,
  128. memberCheck: false,
  129. target: true,
  130. openPageHandle: localStorage.getItem('openPageHandle') || 'blank'
  131. }
  132. },
  133. computed: {
  134. ...mapGetters(['activeNavTag', 'navTagType', 'notice'])
  135. },
  136. watch: {
  137. $route: {
  138. handler(to) {
  139. this.findRoute(to.name)
  140. },
  141. immediate: true
  142. }
  143. },
  144. created() {
  145. this.getLoginUser()
  146. this.verifyIsAdmin()
  147. },
  148. methods: {
  149. goto(name) {
  150. window.log({ c: 'project', d: `goto_${name}` })
  151. // this.$router.push({ name })
  152. if (name === 'env') {
  153. window.open(envUrl, '_self')
  154. } else {
  155. this.$router.push({ name })
  156. }
  157. },
  158. getTarget() {
  159. this.target = !this.target
  160. },
  161. findRoute(routeName) {
  162. for (const element of routes) {
  163. if (element.name === routeName) {
  164. // 先对父元素进行查找
  165. this.$store.dispatch('global/setActiveNavTag', element.name)
  166. } else if (element.children) {
  167. const child = element.children.find((item) => item.name === routeName) // 对子元素进行查找
  168. child
  169. ? this.$store.dispatch('global/setActiveNavTag', element.name)
  170. : '' // 父元素的名字设为路径
  171. }
  172. }
  173. },
  174. // 切换二级导航
  175. changeNavTag(nav) {
  176. window.log({ c: 'entry', d: nav.key })
  177. this.$store.dispatch('global/setActiveNavTag', nav.name) // 设置二级导航的类别
  178. this.$router.push({ name: nav.name }) // 跳转
  179. },
  180. // 设置二级导航类型
  181. setNavTagType(type) {
  182. if (type === 2) {
  183. window.log({ c: 'sys_setting', d: 'change_nav_bar_top' })
  184. } else {
  185. window.log({ c: 'sys_setting', d: 'change_nav_bar_side' })
  186. }
  187. this.$store.dispatch('global/setNavTagType', type)
  188. localStorage.setItem('navTagType', type)
  189. },
  190. setOpenPageHandle(type) {
  191. this.openPageHandle = type
  192. localStorage.setItem('openPageHandle', type)
  193. },
  194. // 获取登录人员信息
  195. async getLoginUser() {
  196. const res = await memberGetLoginInMemberInfoByLdap()
  197. if (res && res.data) this.userInfo = res.data || null
  198. },
  199. // 查看是否为管理员
  200. async verifyIsAdmin() {
  201. const res = await verifyIsAdmin()
  202. if (res.code === 200) this.memberCheck = res.data
  203. },
  204. // 退出登录
  205. layout() {
  206. window.location.href = logoutUrl
  207. },
  208. topHome() {
  209. this.$router.push({ path: '/' })
  210. },
  211. administratorsJump() {
  212. if (this.memberCheck) {
  213. this.$router.push({ name: '管理员' })
  214. }
  215. },
  216. // websocket数据接收
  217. websocketonmessage(e) {
  218. const { hasReminding } = JSON.parse(e.data)
  219. if (hasReminding) {
  220. this.$store.dispatch('data/setNotice', true)
  221. const link = document.querySelector('link')
  222. link.href = link.href.replace(/favicon.ico/, 'favicon-tips.ico')
  223. } else {
  224. this.$store.dispatch('data/setNotice', false)
  225. const link = document.querySelector('link')
  226. link.href = link.href.replace(/favicon-tips.ico/, 'favicon.ico')
  227. }
  228. }
  229. }
  230. }
  231. </script>
  232. <style lang="less" scoped>
  233. .mr10 {
  234. margin-right: 10px;
  235. }
  236. .mb16 {
  237. margin-bottom: 16px;
  238. }
  239. .head-wrapper {
  240. display: flex;
  241. flex-direction: column;
  242. flex-shrink: 0;
  243. z-index: 99;
  244. width: 80px;
  245. align-items: center;
  246. background: #409eff;
  247. font-size: 20px;
  248. color: #333;
  249. padding-top: 17px;
  250. }
  251. .head-logo {
  252. height: 40px;
  253. width: 40px;
  254. margin-bottom: 20px;
  255. .svg-icon {
  256. cursor: pointer;
  257. width: 100%;
  258. height: 100%;
  259. }
  260. }
  261. .nav-tag {
  262. width: 100%;
  263. font-size: 14px;
  264. color: #ffffff;
  265. text-align: center;
  266. margin-bottom: 10px;
  267. padding: 10px 0;
  268. cursor: pointer;
  269. .icon {
  270. position: relative;
  271. color: #ffffff;
  272. height: 27px;
  273. width: 33px;
  274. margin: 7px auto;
  275. font-size: 32px;
  276. }
  277. .svg-icon {
  278. position: absolute;
  279. top: 0;
  280. left: 0;
  281. width: 100%;
  282. height: 100%;
  283. }
  284. .if-notice {
  285. position: absolute;
  286. z-index: 1;
  287. height: 8px;
  288. width: 8px;
  289. background-color: #e02020;
  290. border-radius: 50%;
  291. top: 0;
  292. right: 0;
  293. transform: translateY(-50%);
  294. }
  295. }
  296. .active-nav-tag {
  297. background-color: #1e89f7;
  298. }
  299. .nav-tag-type {
  300. margin-top: auto;
  301. color: #ffffff;
  302. cursor: pointer;
  303. }
  304. .user-tip {
  305. margin-top: 5px;
  306. margin-bottom: 8px;
  307. }
  308. .user-info {
  309. height: 30px;
  310. width: 30px;
  311. display: flex;
  312. justify-content: center;
  313. align-items: center;
  314. background-color: #fff;
  315. border-radius: 50%;
  316. overflow: hidden;
  317. // margin-top: auto;
  318. margin-bottom: 20px;
  319. img {
  320. height: 30px;
  321. width: 30px;
  322. }
  323. }
  324. .user-admin-one {
  325. // height: 190px;
  326. .title {
  327. cursor: no-drop;
  328. .icon {
  329. margin-right: 5px;
  330. font-size: 12px;
  331. color: #409eff;
  332. }
  333. .label {
  334. color: #444;
  335. font-size: 14px;
  336. }
  337. }
  338. .line {
  339. margin-bottom: 10px;
  340. min-height: 21px;
  341. &.clickText {
  342. cursor: pointer;
  343. margin-bottom: 16px;
  344. .label {
  345. color: #409eff;
  346. }
  347. }
  348. }
  349. .item {
  350. margin-left: 18px;
  351. cursor: pointer;
  352. .label {
  353. color: #444;
  354. font-size: 12px;
  355. .label-text {
  356. display: inline-block;
  357. vertical-align: bottom;
  358. margin-right: 4px;
  359. }
  360. }
  361. .fontSize14 {
  362. font-size: 14px;
  363. }
  364. }
  365. .outLogin {
  366. display: inline-block;
  367. margin-top: 5px;
  368. .icon {
  369. display: inline-block;
  370. color: #409eff;
  371. font-size: 14px;
  372. }
  373. .label {
  374. color: #409eff;
  375. font-size: 14px;
  376. }
  377. }
  378. // width: 95px;
  379. // display: flex;
  380. // flex-direction: column;
  381. // display: grid;
  382. // grid-template-rows: 47px 1px 47px 1px 47px;
  383. // justify-items: center;
  384. // align-items: center;
  385. // .line {
  386. // width: 100%;
  387. // height: 1px;
  388. // background-color: rgba(112, 112, 112, 0.2);
  389. // }
  390. }
  391. // .user-control {
  392. // width: 95px;
  393. // display: flex;
  394. // flex-direction: column;
  395. // display: grid;
  396. // grid-template-rows: 47px 1px 47px 1px 47px;
  397. // justify-items: center;
  398. // align-items: center;
  399. // .line {
  400. // width: 100%;
  401. // height: 1px;
  402. // background-color: rgba(112, 112, 112, 0.2);
  403. // }
  404. // }
  405. </style>
  406. <style lang="less" scoped>
  407. .head-popover {
  408. box-shadow: 10px 0px 11px #dedede;
  409. /deep/ .ant-popover-inner-content {
  410. padding: 0;
  411. }
  412. }
  413. .nav-div1 {
  414. width: 25px;
  415. height: 50px;
  416. border-radius: 0 50px 50px 0;
  417. line-height: 50px;
  418. background: #6cb5ff;
  419. position: absolute;
  420. bottom: 172px;
  421. left: 0;
  422. border: 1px solid #6cb5ff;
  423. animation: myfirsts 0.5s;
  424. }
  425. .nav-div2 {
  426. bottom: 137px;
  427. width: 60px;
  428. height: 120px;
  429. line-height: 120px;
  430. border-radius: 0 80px 80px 0;
  431. background: #6cb5ff;
  432. position: absolute;
  433. left: 0;
  434. animation: myfirst 1s;
  435. }
  436. @keyframes myfirst {
  437. from {
  438. bottom: 172px;
  439. width: 25px;
  440. height: 50px;
  441. line-height: 50px;
  442. }
  443. to {
  444. bottom: 137px;
  445. width: 60px;
  446. height: 120px;
  447. line-height: 120px;
  448. }
  449. }
  450. @keyframes myfirsts {
  451. from {
  452. bottom: 137px;
  453. width: 60px;
  454. height: 120px;
  455. line-height: 120px;
  456. }
  457. to {
  458. bottom: 172px;
  459. width: 25px;
  460. height: 50px;
  461. line-height: 50px;
  462. }
  463. }
  464. .nav-div3 {
  465. width: 25px;
  466. height: 50px;
  467. line-height: 50px;
  468. background: #fff;
  469. bottom: 172px;
  470. border: 1px solid #fff;
  471. opacity: 0.63;
  472. }
  473. .nav-div4 {
  474. width: 20px;
  475. height: 40px;
  476. line-height: 45px;
  477. background: #fff;
  478. bottom: 177px;
  479. border: 1px solid #fff;
  480. }
  481. .div-child {
  482. text-align: right;
  483. margin-right: 19px;
  484. line-height: 61px;
  485. cursor: pointer;
  486. opacity: 1;
  487. animation: myfirs 3s;
  488. }
  489. @keyframes myfirs {
  490. from {
  491. opacity: 0;
  492. }
  493. to {
  494. opacity: 1;
  495. }
  496. }
  497. .nav-circular {
  498. position: absolute;
  499. left: 0;
  500. border-radius: 0 50px 50px 0;
  501. cursor: pointer;
  502. }
  503. </style>