Navbar.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. <template>
  2. <div class="navbar">
  3. <!-- <hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> -->
  4. <router-link
  5. key="collapse"
  6. style="display: flex; align-items: center; padding-left: 30px"
  7. to="/"
  8. >
  9. <img
  10. src="@/assets/images/base/logo.png"
  11. class="sidebar-logo"
  12. style="width: 129px; height: 37px"
  13. />
  14. </router-link>
  15. <!-- <breadcrumb class="breadcrumb-container" /> -->
  16. <div class="indexlayout-top-menu">
  17. <!-- :class="{'active': getTopMenuActive === route.path}" -->
  18. <!-- el-scrollbar -->
  19. <el-scrollbar
  20. class="horizontal-scrollbar"
  21. style="overflow: hidden; height: 100%"
  22. >
  23. <template v-for="route in permission_routes">
  24. <app-link
  25. v-if="!route.hidden"
  26. :to="route.path"
  27. :key="route.id"
  28. class="indexlayout-top-menu-li"
  29. :class="{ active: getTopMenuActive === route.path }"
  30. >
  31. <span>{{ route.meta.title }}</span>
  32. </app-link>
  33. </template>
  34. </el-scrollbar>
  35. </div>
  36. <div class="right-menu">
  37. <el-popover
  38. placement="bottom"
  39. trigger="hover"
  40. style="display: flex; height: 89px"
  41. >
  42. <div class="popover-container" style="text-align: center">OA审批</div>
  43. <div
  44. style="
  45. display: flex;
  46. align-items: center;
  47. justify-content: center;
  48. height: 89px;
  49. "
  50. class="msginfo"
  51. @click="gotoOa"
  52. slot="reference"
  53. >
  54. <img
  55. src="@/assets/images/base/instruction-icon.png"
  56. width="24px"
  57. height="24px"
  58. />
  59. <!-- <div class="active"></div> -->
  60. </div>
  61. </el-popover>
  62. <el-popover
  63. v-if="isShowIns"
  64. placement="bottom"
  65. trigger="hover"
  66. style="display: flex; height: 89px"
  67. >
  68. <div class="popover-container" style="text-align: center">操作手册</div>
  69. <div
  70. style="
  71. display: flex;
  72. align-items: center;
  73. justify-content: center;
  74. height: 89px;
  75. "
  76. class="msginfo"
  77. @click="openIns"
  78. slot="reference"
  79. >
  80. <img
  81. src="@/assets/images/base/instruction-icon.png"
  82. width="24px"
  83. height="24px"
  84. />
  85. <!-- <div class="active"></div> -->
  86. </div>
  87. </el-popover>
  88. <el-popover
  89. placement="bottom"
  90. trigger="hover"
  91. style="display: flex; height: 89px"
  92. >
  93. <div class="popover-container" style="text-align: center">系统日志</div>
  94. <div
  95. style="
  96. display: flex;
  97. align-items: center;
  98. justify-content: center;
  99. height: 89px;
  100. "
  101. class="msginfo"
  102. v-permission="'/journal'"
  103. @click="gotoRecode"
  104. slot="reference"
  105. >
  106. <img
  107. src="@/assets/images/base/base-bell.png"
  108. width="24px"
  109. height="24px"
  110. />
  111. <!-- <div class="active"></div> -->
  112. </div>
  113. </el-popover>
  114. <div class="left-menu">
  115. <el-popover
  116. placement="top-start"
  117. width="300"
  118. trigger="hover"
  119. style="display: flex; height: 89px"
  120. >
  121. <div class="popover-container">
  122. <el-tag
  123. class="navbar_tag"
  124. type="info"
  125. v-for="item in organNameList"
  126. :key="item"
  127. >{{ item }}</el-tag
  128. >
  129. </div>
  130. <span
  131. slot="reference"
  132. class="msginfo"
  133. style="
  134. display: flex;
  135. align-items: center;
  136. justify-content: center;
  137. height: 89px;
  138. "
  139. >
  140. <!-- {{ organName.length > 10 ? organName.substr(0, 10) + "..." : organName }} -->
  141. <!-- <i class="el-icon-s-home" style="font-size: 23px; color: #1A1A1A;"></i> -->
  142. <img
  143. src="@/assets/images/base/base-home.png"
  144. width="24px"
  145. height="24px"
  146. />
  147. </span>
  148. </el-popover>
  149. </div>
  150. <el-dropdown class="avatar-container" trigger="click">
  151. <div class="avatar-wrapper">
  152. <img
  153. v-if="$store.getters.avatar"
  154. :src="$store.getters.avatar"
  155. class="user-avatar"
  156. />
  157. <img
  158. v-else
  159. class="user-avatar"
  160. src="@/assets/images/base/placehorder-icon.png"
  161. />
  162. <!-- <i class="el-icon-caret-bottom" /> -->
  163. <span>{{ username }}</span>
  164. </div>
  165. <el-dropdown-menu slot="dropdown" class="user-dropdown">
  166. <!-- divided -->
  167. <el-dropdown-item>
  168. <span style="display: block" @click="resetPassWord">修改密码</span>
  169. </el-dropdown-item>
  170. <el-dropdown-item>
  171. <span style="display: block" @click="logout">退出</span>
  172. </el-dropdown-item>
  173. </el-dropdown-menu>
  174. </el-dropdown>
  175. </div>
  176. <el-dialog
  177. title="修改密码"
  178. width="500px"
  179. append-to-body
  180. :visible.sync="resetVisible"
  181. >
  182. <el-form
  183. :model="resetForm"
  184. label-position="right"
  185. label-width="100px"
  186. ref="pwdForm"
  187. >
  188. <el-form-item label="手机号" prop="phone">
  189. <div>{{ this.$store.getters.phone }}</div>
  190. </el-form-item>
  191. <el-form-item
  192. label="新密码"
  193. :rules="[
  194. { required: true, message: '密码不能为空', trigger: 'blur' },
  195. {
  196. pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/,
  197. message: '密码为6-20位数字和字母组合',
  198. trigger: 'blur',
  199. },
  200. ]"
  201. prop="password"
  202. >
  203. <el-input
  204. v-model.trim="resetForm.password"
  205. type="password"
  206. style="width: 180px"
  207. autocomplete="off"
  208. ></el-input>
  209. </el-form-item>
  210. <el-form-item
  211. label="再次输入"
  212. :rules="[
  213. { required: true, message: '密码不能为空', trigger: 'blur' },
  214. {
  215. pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/,
  216. message: '密码为6-20位数字和字母组合',
  217. trigger: 'blur',
  218. },
  219. ]"
  220. prop="password2"
  221. >
  222. <el-input
  223. v-model.trim="resetForm.password2"
  224. type="password"
  225. style="width: 180px"
  226. autocomplete="off"
  227. ></el-input>
  228. </el-form-item>
  229. <el-form-item
  230. label="验证码"
  231. :rules="[
  232. { required: true, message: '验证码不能为空', trigger: 'blur' },
  233. ]"
  234. prop="authCode"
  235. style=""
  236. >
  237. <el-input
  238. v-model.trim="resetForm.authCode"
  239. style="width: 180px"
  240. autocomplete="off"
  241. ></el-input>
  242. <el-button :disabled="isDisable" @click="getCode">{{
  243. btnName
  244. }}</el-button>
  245. </el-form-item>
  246. </el-form>
  247. <div slot="footer" class="dialog-footer">
  248. <el-button @click="resetVisible = false">取 消</el-button>
  249. <el-button type="primary" @click="submitResetPassWord">确 定</el-button>
  250. </div>
  251. </el-dialog>
  252. <portal-target name="AppMain" ref="target">
  253. <instructions ref="instructions" @checkShow="checkShow" />
  254. </portal-target>
  255. </div>
  256. </template>
  257. <script>
  258. import qs from "qs";
  259. import Logo from "./Sidebar/Logo";
  260. import { mapGetters } from "vuex";
  261. // import Breadcrumb from '@/components/Breadcrumb'
  262. // import Hamburger from '@/components/Hamburger'
  263. import { resetPassword } from "@/api/buildTeam";
  264. import AppLink from "./Sidebar/Link";
  265. import { getBelongTopMenuPath } from "@/utils/permission";
  266. import instructions from "./instructions";
  267. import axios from 'axios'
  268. export default {
  269. data() {
  270. return {
  271. username: "",
  272. organName: this.$store.getters.organName,
  273. organNameList: [],
  274. resetVisible: false,
  275. resetForm: {
  276. phone: "",
  277. authCode: "",
  278. password: "",
  279. password2: "",
  280. },
  281. isDisable: false, // 是否允许发送验证码
  282. timerCount: 60,
  283. btnName: "获取验证码",
  284. isShowIns: false,
  285. };
  286. },
  287. components: {
  288. AppLink,
  289. instructions,
  290. // Breadcrumb,
  291. // Hamburger
  292. },
  293. computed: {
  294. ...mapGetters(["sidebar", "avatar", "permission_routes"]),
  295. getTopMenuActive() {
  296. let route = this.$route;
  297. // (route, getBelongTopMenuPath(route))
  298. return getBelongTopMenuPath(route);
  299. },
  300. },
  301. mounted() {
  302. // 手动加入
  303. this.toggleSideBar();
  304. this.username = this.$store.getters.name;
  305. this.organNameList = this.organName.split(",") || [];
  306. },
  307. methods: {
  308. toggleSideBar() {
  309. this.$store.dispatch("app/toggleSideBar");
  310. },
  311. async logout() {
  312. await this.$store.dispatch("user/logout");
  313. localStorage.removeItem("firstMenuUrl");
  314. // await this.$store.dispatch("permission/removePermission")
  315. this.$router.push(`/login`);
  316. window.location.reload();
  317. },
  318. gotoRecode() {
  319. this.$router.push("/journal/journal");
  320. },
  321. resetPassWord() {
  322. this.resetVisible = true;
  323. },
  324. submitResetPassWord() {
  325. if (this.resetForm.password !== this.resetForm.password2) {
  326. this.$message.error("两次密码必须相同");
  327. return;
  328. }
  329. this.$refs["pwdForm"].validate((res) => {
  330. if (res) {
  331. // 发请求
  332. resetPassword({
  333. authCode: this.resetForm.authCode,
  334. mobile: this.$store.getters.phone,
  335. newPassword: this.resetForm.password,
  336. }).then((res) => {
  337. if (res.code == 200) {
  338. // 修改成功
  339. this.$message.success("修改成功");
  340. this.logout();
  341. }
  342. });
  343. }
  344. });
  345. },
  346. getCode() {
  347. // 获取验证码
  348. if (!this.$store.getters.phone) {
  349. this.$message.error("请输入正确的手机号");
  350. return;
  351. }
  352. if (!this.isDisable) {
  353. this.isDisable = true;
  354. // 发请求成功后开启定时器
  355. // 发送验证码
  356. axios
  357. .post(
  358. "/api-web/code/sendSms",
  359. qs.stringify({ mobile: this.$store.getters.phone })
  360. )
  361. .then((res) => {
  362. if (res.data.code == 200) {
  363. let timer = setInterval((res) => {
  364. if (this.timerCount <= 0) {
  365. clearInterval(timer);
  366. this.isDisable = false;
  367. this.btnName = "获取验证码";
  368. this.timerCount = 60;
  369. } else {
  370. this.timerCount--;
  371. this.btnName = `${this.timerCount}s后重试`;
  372. }
  373. }, 1000);
  374. }
  375. });
  376. }
  377. },
  378. openIns() {
  379. this.$refs.instructions.showInstructions();
  380. },
  381. checkShow(val) {
  382. this.isShowIns = val;
  383. },
  384. gotoOa(){
  385. window.open('http://oadev.dayaedu.com/')
  386. }
  387. },
  388. watch: {
  389. resetVisible(val) {
  390. if (!val) {
  391. this.resetForm = {
  392. phone: "",
  393. authCode: "",
  394. password: "",
  395. password2: "",
  396. };
  397. }
  398. },
  399. },
  400. };
  401. </script>
  402. <style lang="scss" scoped>
  403. .navbar_tag {
  404. margin: 0 5px 8px;
  405. }
  406. .indexlayout-top-menu {
  407. padding-left: 57px;
  408. height: 90px;
  409. line-height: 88px;
  410. flex: 1;
  411. display: flex;
  412. overflow: hidden;
  413. /* overflow-x: auto; */
  414. .indexlayout-top-menu-li {
  415. display: inline-block;
  416. padding: 0 5px;
  417. height: 90px;
  418. text-decoration: none;
  419. color: #f2f2f2;
  420. font-size: 16px;
  421. transition: all 0.3s ease;
  422. span {
  423. // display: block;
  424. transition: all 0.3s ease;
  425. padding: 10px 20px;
  426. }
  427. &:hover,
  428. &.active {
  429. color: #14928a;
  430. span {
  431. background: #fff;
  432. border-radius: 6px;
  433. }
  434. }
  435. &.active span {
  436. font-weight: bold;
  437. }
  438. }
  439. .breadcrumb {
  440. line-height: 90px;
  441. margin-left: 10px;
  442. .el-breadcrumb__item {
  443. display: inline-block;
  444. float: none;
  445. }
  446. }
  447. }
  448. .popover-container {
  449. max-height: 350px;
  450. overflow-y: scroll;
  451. }
  452. .navbar {
  453. display: flex;
  454. flex-direction: row;
  455. justify-content: space-between;
  456. height: 90px;
  457. overflow: hidden;
  458. position: relative;
  459. z-index: 2000;
  460. background: #14928a;
  461. box-shadow: 0px 8px 20px 0px rgba(0, 0, 0, 0.1);
  462. h2 {
  463. font-size: 18px;
  464. line-height: 90px;
  465. margin: 0 0 0 30px;
  466. display: inline-block;
  467. }
  468. .hamburger-container {
  469. line-height: 90px;
  470. height: 100%;
  471. float: left;
  472. cursor: pointer;
  473. transition: background 0.3s;
  474. -webkit-tap-highlight-color: transparent;
  475. &:hover {
  476. background: rgba(0, 0, 0, 0.025);
  477. }
  478. }
  479. .breadcrumb-container {
  480. float: left;
  481. }
  482. .left-menu {
  483. line-height: 90px;
  484. // padding-right: 22px;
  485. font-size: 16px;
  486. color: #fff;
  487. .topIcon {
  488. width: 20px;
  489. height: 25px;
  490. }
  491. }
  492. .right-menu {
  493. min-width: 154px;
  494. float: right;
  495. height: 100%;
  496. line-height: 90px;
  497. display: flex;
  498. flex-direction: row;
  499. justify-content: flex-start;
  500. &:focus {
  501. outline: none;
  502. }
  503. .msginfo.ins {
  504. img {
  505. width: 18px;
  506. height: 23px;
  507. }
  508. }
  509. .msginfo {
  510. display: flex;
  511. flex-direction: row;
  512. justify-content: flex-start;
  513. align-items: center;
  514. padding-right: 25px;
  515. position: relative;
  516. cursor: pointer;
  517. img {
  518. width: 24px;
  519. height: 24px;
  520. }
  521. .active {
  522. position: absolute;
  523. width: 7px;
  524. height: 7px;
  525. background-color: #f97215;
  526. border-radius: 50%;
  527. top: 20px;
  528. right: -4px;
  529. }
  530. }
  531. .right-menu-item {
  532. display: inline-block;
  533. padding: 0 8px;
  534. height: 100%;
  535. font-size: 14px;
  536. color: #5a5e66;
  537. vertical-align: text-bottom;
  538. &.hover-effect {
  539. cursor: pointer;
  540. transition: background 0.3s;
  541. &:hover {
  542. background: rgba(0, 0, 0, 0.025);
  543. }
  544. }
  545. }
  546. .avatar-container {
  547. height: 90px;
  548. margin-right: 42px;
  549. cursor: pointer;
  550. .avatar-wrapper {
  551. position: relative;
  552. display: flex;
  553. flex-direction: row;
  554. justify-content: flex-start;
  555. align-items: center;
  556. span {
  557. margin-left: 8px;
  558. font-size: 14px;
  559. font-weight: 500;
  560. // color: rgba(68, 68, 68, 1);
  561. color: #fff;
  562. }
  563. .user-avatar {
  564. cursor: pointer;
  565. width: 32px;
  566. height: 32px;
  567. border: 2px solid #f0f2f5;
  568. border-radius: 50%;
  569. }
  570. .el-icon-caret-bottom {
  571. cursor: pointer;
  572. position: absolute;
  573. right: -20px;
  574. top: 25px;
  575. font-size: 14px;
  576. }
  577. }
  578. }
  579. }
  580. }
  581. </style>