Navbar.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. <template>
  2. <div class="navbar">
  3. <div class="left-menu">
  4. <hamburger
  5. id="hamburger-container"
  6. :is-active="sidebar.opened"
  7. class="hamburger-container"
  8. @toggleClick="toggleSideBar"
  9. />
  10. <template v-if="device !== 'mobile'">
  11. <breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
  12. </template>
  13. </div>
  14. <div class="right-menu">
  15. <div class="right-menu-item">
  16. <company-select
  17. ref="companySelect"
  18. select-all
  19. global
  20. placeholder="请选择供应商"
  21. :style="{ width: device === 'mobile' ? '200px' : '400px' }"
  22. />
  23. </div>
  24. <el-tooltip placement="bottom" :content="switchAccountModeText">
  25. <i
  26. v-if="isSupertube"
  27. class="el-icon-sort right-menu-item hover-effect"
  28. style="
  29. height: 50px;
  30. width: 35px;
  31. line-height: 52px;
  32. font-size: 22px;
  33. transform: rotate(90deg);
  34. "
  35. @click="onSwitchCompanyMode"
  36. />
  37. </el-tooltip>
  38. <el-tooltip
  39. v-if="device !== 'mobile'"
  40. placement="bottom"
  41. content="登录工单管理系统"
  42. >
  43. <p
  44. class="username"
  45. style="font-size:14px;color:#5a5e66;font-weight:500;line-height:54px;margin:0px 5px;cursor:pointer"
  46. @click="openSettlementSystem(GDurl)"
  47. >
  48. 工单
  49. </p>
  50. </el-tooltip>
  51. <el-tooltip
  52. v-if="device !== 'mobile'"
  53. placement="bottom"
  54. content="登录采销结算平台"
  55. >
  56. <i
  57. class="el-icon-s-promotion right-menu-item hover-effect"
  58. style="height: 50px; width: 40px; line-height: 52px; font-size: 22px"
  59. @click="openSettlementSystem(JSurl)"
  60. />
  61. </el-tooltip>
  62. <template v-if="device !== 'mobile'">
  63. <i
  64. v-if="isShow"
  65. class="el-icon-message-solid right-menu-item hover-effect shake"
  66. style="height: 50px; width: 40px; line-height: 52px; font-size: 22px"
  67. @click="openNotice()"
  68. />
  69. <screenfull id="screenfull" class="right-menu-item hover-effect" />
  70. <!-- <el-tooltip content="Global Size" effect="dark" placement="bottom">
  71. <size-select id="size-select" class="right-menu-item hover-effect" />
  72. </el-tooltip> -->
  73. </template>
  74. <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
  75. <div class="avatar-wrapper">
  76. <!-- <img :src="avatar + '?imageView2/1/w/80/h/80'" class="user-avatar"> -->
  77. <template v-if="userInfo.nickname && userInfo.nickname.length <= 3">
  78. <div class="username">
  79. {{ userInfo.nickname }}
  80. <i class="el-icon-caret-bottom" />
  81. </div>
  82. </template>
  83. <template v-if="userInfo.nickname && userInfo.nickname.length > 3">
  84. <el-tooltip
  85. class="item"
  86. effect="dark"
  87. :content="userInfo.nickname"
  88. placement="left-start"
  89. >
  90. <div class="username">
  91. {{ getUserName(userInfo.nickname) }}
  92. <i class="el-icon-caret-bottom" />
  93. </div>
  94. </el-tooltip>
  95. </template>
  96. </div>
  97. <el-dropdown-menu slot="dropdown">
  98. <!-- <router-link to="/person/my-message">
  99. <el-dropdown-item>我的信息</el-dropdown-item>
  100. </router-link>
  101. <router-link to="/person/change-phone">
  102. <el-dropdown-item>更换手机号</el-dropdown-item>
  103. </router-link> -->
  104. <el-dropdown-item @click.native="visible = true">
  105. <span style="display: block">修改密码</span>
  106. </el-dropdown-item>
  107. <el-dropdown-item @click.native="logout">
  108. <span style="display: block">退出登录</span>
  109. </el-dropdown-item>
  110. </el-dropdown-menu>
  111. </el-dropdown>
  112. </div>
  113. <!-- <el-select
  114. class="fr right-menu-item"
  115. v-model="companyNo"
  116. :size="'mini'"
  117. style="width: 350px; margin: 12px 16px 0 0"
  118. @change="business_companyNo_change"
  119. placeholder="请选择供应商"
  120. >
  121. <el-option
  122. v-for="(item, index) in companyList"
  123. :key="item.supplierNo + item.id + index"
  124. :label="item.supplierName"
  125. :disabled="item.status !== '1'"
  126. :value="item.supplierNo"
  127. >
  128. </el-option>
  129. </el-select> -->
  130. <password-modal :visible.sync="visible" />
  131. <el-dialog
  132. title="系统公告"
  133. :center="true"
  134. align="left"
  135. top="6vh"
  136. width="900px"
  137. :close-on-click-modal="false"
  138. :visible.sync="showModel"
  139. element-loading-text="拼命加载中"
  140. element-loading-spinner="el-icon-loading"
  141. element-loading-background="rgba(0, 0, 0, 0.8)"
  142. append-to-body
  143. @close="submit"
  144. >
  145. <el-card style="margin-top: -20px">
  146. <el-row v-if="activeMsg !== null" :gutter="10">
  147. <el-col :span="24">
  148. <div style="padding: 0 0 22px 0">
  149. <el-alert
  150. :closable="false"
  151. show-icon
  152. center
  153. class="my-el-alert"
  154. :title="activeMsg.module"
  155. :type="activeMsg.sys_type === 'VER' ? 'success' : 'warning'"
  156. />
  157. </div>
  158. <el-form
  159. :size="'mini'"
  160. label-position="left"
  161. label-width="82px"
  162. class="demo-table-expand"
  163. style="padding-left: 25px"
  164. >
  165. <el-row>
  166. <el-col v-if="activeMsg.sys_type === 'VER'" :span="12">
  167. <el-form-item label="版本编号:">
  168. <p style="margin: 0">{{ activeMsg.version }}</p>
  169. </el-form-item>
  170. </el-col>
  171. <el-col :span="activeMsg.sys_type === 'VER' ? 12 : 24">
  172. <el-form-item
  173. :label="activeMsg.sys_type === 'VER' ? '更新时间:' : '预计时间:'"
  174. >
  175. <p style="margin: 0">
  176. {{ activeMsg.addtime }}
  177. </p>
  178. </el-form-item>
  179. </el-col>
  180. <el-col :span="24">
  181. <el-form-item label="更新内容:">
  182. <p style="margin: 0" v-html="activeMsg.system" />
  183. </el-form-item>
  184. </el-col>
  185. <el-col :span="24" style="text-align: right">
  186. <el-checkbox
  187. v-model="checked"
  188. class="fl"
  189. style="padding-top: 5px"
  190. >我已知晓,后续不再提示!</el-checkbox>
  191. <el-button
  192. type="primary"
  193. plain
  194. :size="'mini'"
  195. @click="submit"
  196. >关闭
  197. </el-button>
  198. </el-col>
  199. </el-row>
  200. </el-form>
  201. </el-col>
  202. </el-row>
  203. </el-card>
  204. </el-dialog>
  205. </div>
  206. </template>
  207. <script>
  208. import { mapGetters } from 'vuex'
  209. import asyncRequest from '@/apis/service/system/updates'
  210. import resToken from '@/mixins/resToken'
  211. import CompanySelect from './company-select/index.vue'
  212. import PasswordModal from '@/layout/components/password-modal/index.vue'
  213. import config from '@/config/index'
  214. import {
  215. getNotice,
  216. setNotice,
  217. get_business_companyNo,
  218. get_business_company,
  219. getToken
  220. } from '@/utils/auth'
  221. import CryptoJS from 'crypto-js'
  222. import { userStoreActions } from '@/store/modules/user'
  223. import { accountLevels } from '@/assets/js/statusList'
  224. import { userInfo } from 'os'
  225. export default {
  226. computed: {
  227. ...mapGetters([
  228. 'sidebar',
  229. 'avatar',
  230. 'device',
  231. 'userInfo',
  232. 'currentLevel',
  233. 'navList',
  234. 'isSupertube'
  235. ]),
  236. switchAccountModeText() {
  237. return this.currentLevel === '3' ? '切换到业务公司' : '切换到供应商'
  238. }
  239. },
  240. components: {
  241. CompanySelect,
  242. PasswordModal
  243. },
  244. mixins: [resToken],
  245. data() {
  246. return {
  247. JSurl: config.settlementPlatformUrl + '/#/accept?t=',
  248. GDurl: config.GDUrl + '#/demand/index?t=',
  249. companyNo: '',
  250. companyNoName: '',
  251. showModel: false,
  252. loading: false,
  253. isShow: true,
  254. statsTime: 0,
  255. endTime: 0,
  256. checked: true,
  257. visible: false,
  258. lastNotice: null, // 最后一次提示时间
  259. parmValue: {
  260. type: '',
  261. page: 1, // 页码
  262. size: 15 // 每页显示条数
  263. },
  264. activeMsg: null // 消息展示对象
  265. }
  266. },
  267. mounted() {
  268. this.companyNo = get_business_companyNo() || ''
  269. this.companyNoName = get_business_company() || ''
  270. this.openNotice(true)
  271. },
  272. methods: {
  273. getUserName(username) {
  274. const chunks = username.split('')
  275. return chunks[0] + chunks[1] + '...'
  276. },
  277. openSettlementSystem: function(url) {
  278. // 加密token
  279. // const encJson = CryptoJS.AES.encrypt(
  280. // JSON.stringify({ token: getToken() }),
  281. // config.secretKey
  282. // )
  283. // const encData = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(encJson))
  284. // // 跳转至结算平台携带加密后的token
  285. // console.log(url + encData)
  286. // window.open(url + encData)
  287. this.$alert('正在开发中', '提示', {
  288. type: 'warning'
  289. })
  290. },
  291. async openNotice(is) {
  292. if (getNotice() && getNotice().length > 0) {
  293. this.lastNotice = JSON.parse(getNotice())
  294. } else {
  295. this.lastNotice = null
  296. }
  297. const { code, count, item, message } = await this.initData()
  298. if (code === 0) {
  299. if (count != 0) {
  300. this.activeMsg = item
  301. if (is) {
  302. this.typeShow()
  303. } else {
  304. this.showModel = true
  305. }
  306. } else {
  307. this.$message.warning('暂无系统消息!')
  308. }
  309. } else if (code >= 100 && code <= 104) {
  310. await this.logout()
  311. } else {
  312. this.$message.warning(message)
  313. }
  314. },
  315. business_companyNo_change(e) {
  316. // const index = this.companyList.findIndex((si) => si.supplierNo === e);
  317. // if (index !== -1) {
  318. // const { supplierNo, supplierName } = this.companyList[index];
  319. // this.companyNo = supplierNo;
  320. // this.companyNoName = supplierName;
  321. // this.$store
  322. // .dispatch("user/change_company", { supplierNo, supplierName })
  323. // .then((res) => {
  324. // console.log(res);
  325. // })
  326. // .catch(() => {});
  327. // }
  328. },
  329. async initData() {
  330. const res = {
  331. code: 0,
  332. count: 0,
  333. item: {},
  334. message: ''
  335. }
  336. this.loading = true
  337. const { code, data, message } = await asyncRequest.list(this.parmValue)
  338. this.loading = false
  339. res.code = code
  340. res.message = message
  341. if (code === 0) {
  342. const { list, count } = data
  343. res.count = count
  344. if (count !== 0) {
  345. res.item = JSON.parse(JSON.stringify(list[0]))
  346. }
  347. }
  348. return res
  349. },
  350. typeShow() {
  351. const is = this.is_Tips()
  352. if (!is) {
  353. return
  354. }
  355. if (this.lastNotice + '' === 'null' && is) {
  356. this.showModel = true
  357. } else {
  358. const { addtime: laddtime, type: ltype, sys_type: lsys_type } = this.lastNotice
  359. const { sys_type, addtime } = this.activeMsg
  360. if (laddtime === addtime && lsys_type === sys_type) {
  361. if (ltype + '' === '1') {
  362. this.showModel = false
  363. } else {
  364. this.showModel = true
  365. }
  366. } else {
  367. this.showModel = true
  368. }
  369. }
  370. },
  371. is_Tips() {
  372. const nowtime = new Date().valueOf()
  373. const { sys_type, addtime } = this.activeMsg
  374. const timeV = new Date(addtime).valueOf()
  375. if (sys_type === 'VER') {
  376. this.statsTime = timeV
  377. this.endTime = this.statsTime + 1000 * 60 * 60 * 24 * 7
  378. if (nowtime >= this.statsTime && nowtime <= this.endTime) {
  379. return true
  380. } else {
  381. return false
  382. }
  383. } else {
  384. this.statsTime = 0
  385. this.endTime = timeV
  386. if (nowtime <= this.endTime) {
  387. return true
  388. } else {
  389. return false
  390. }
  391. }
  392. },
  393. toggleSideBar() {
  394. this.$store.dispatch('app/toggleSideBar')
  395. },
  396. async logout() {
  397. await this.$store.dispatch('user/logout')
  398. this.$router.push(`/login?redirect=${this.$route.fullPath}`)
  399. },
  400. submit() {
  401. this.page_set_notice()
  402. this.showModel = false
  403. },
  404. // 保存提交结果
  405. page_set_notice() {
  406. const { sys_type, addtime } = this.activeMsg
  407. const model = {
  408. type: this.checked ? '1' : '0',
  409. sys_type: sys_type,
  410. addtime: addtime
  411. }
  412. setNotice(JSON.stringify(model))
  413. },
  414. // 切换以供应商或业务公司视角
  415. async onSwitchCompanyMode() {
  416. const level =
  417. this.currentLevel === accountLevels.supplier
  418. ? accountLevels.super
  419. : accountLevels.supplier
  420. this.$refs.companySelect && this.$refs.companySelect.selectAllCompany()
  421. this.$store.commit(userStoreActions.setCompanyList, [])
  422. this.$store.commit(userStoreActions.setCurrentLevel, level)
  423. await this.$store.dispatch(userStoreActions.reloadMenu, level)
  424. const parentRoute = this.navList[0]
  425. if (!parentRoute) return
  426. const toRoute = parentRoute.children[0]
  427. if (!toRoute) return
  428. const { url } = toRoute
  429. this.$router.replace('/reload?redirect=' + url.split('/index')[0])
  430. }
  431. }
  432. }
  433. </script>
  434. <style lang="scss" scoped>
  435. @keyframes shake {
  436. /* 水平抖动,核心代码 */
  437. 10%,
  438. 90% {
  439. transform: translate3d(-1px, 0, 0);
  440. }
  441. 20%,
  442. 80% {
  443. transform: translate3d(+2px, 0, 0);
  444. }
  445. 30%,
  446. 70% {
  447. transform: translate3d(-4px, 0, 0);
  448. }
  449. 40%,
  450. 60% {
  451. transform: translate3d(+4px, 0, 0);
  452. }
  453. 50% {
  454. transform: translate3d(-4px, 0, 0);
  455. }
  456. }
  457. .shake {
  458. animation: shake 800ms ease-in-out;
  459. }
  460. .navbar {
  461. height: 50px;
  462. position: relative;
  463. background: #fff;
  464. box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
  465. display: flex;
  466. justify-content: space-between;
  467. .left-menu {
  468. display: flex;
  469. max-width: 1300px;
  470. .hamburger-container {
  471. line-height: 46px;
  472. height: 100%;
  473. cursor: pointer;
  474. transition: background 0.3s;
  475. -webkit-tap-highlight-color: transparent;
  476. &:hover {
  477. background: rgba(0, 0, 0, 0.025);
  478. }
  479. }
  480. .breadcrumb-container {
  481. display: flex;
  482. flex-wrap: nowrap;
  483. overflow: hidden;
  484. // width: 500px;
  485. //min-width: calc(1200px - 200px - 150px);
  486. }
  487. }
  488. .errLog-container {
  489. display: inline-block;
  490. vertical-align: top;
  491. }
  492. .right-menu {
  493. height: 100%;
  494. line-height: 50px;
  495. display: flex;
  496. flex-wrap: nowrap;
  497. &:focus {
  498. outline: none;
  499. }
  500. .right-menu-item {
  501. display: inline-block;
  502. padding: 0 8px;
  503. height: 100%;
  504. font-size: 18px;
  505. color: #5a5e66;
  506. vertical-align: text-bottom;
  507. &.hover-effect {
  508. cursor: pointer;
  509. transition: background 0.3s;
  510. &:hover {
  511. background: rgba(0, 0, 0, 0.025);
  512. }
  513. }
  514. }
  515. .avatar-container {
  516. margin-right: 30px;
  517. .username {
  518. float: right;
  519. font-size: 14px;
  520. margin-left: 10px;
  521. margin-bottom: 10px;
  522. white-space: nowrap;
  523. }
  524. .avatar-wrapper {
  525. margin-top: 5px;
  526. position: relative;
  527. display: flex;
  528. .user-avatar {
  529. cursor: pointer;
  530. width: 40px;
  531. height: 40px;
  532. border-radius: 10px;
  533. }
  534. .el-icon-caret-bottom {
  535. cursor: pointer;
  536. position: absolute;
  537. right: -20px;
  538. top: 25px;
  539. font-size: 12px;
  540. }
  541. }
  542. }
  543. }
  544. }
  545. </style>