topWindow.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. <template>
  2. <view class="header">
  3. <!-- #ifdef H5 -->
  4. <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
  5. style="position: absolute; width: 0; height: 0">
  6. <symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" id="icon-bug">
  7. <path
  8. d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z">
  9. </path>
  10. </symbol>
  11. </svg>
  12. <!-- #endif -->
  13. <view class="navbar" :class="{'navbar-mini':!matchLeftWindow,'popup-menu':popupMenuOpened}">
  14. <view class="navbar-left">
  15. <view class="logo pointer" @click="linkTo">
  16. <image class="logo-image" :src="logo" mode="heightFix"></image>
  17. <text class="logo-text">{{appName}}</text>
  18. </view>
  19. <uni-icons @click="toggleSidebar" type="bars" class="menu-icon" size="30" color="#999"></uni-icons>
  20. </view>
  21. <view class="navbar-middle">
  22. <text class="title-text">{{navigationBarTitleText}}</text>
  23. </view>
  24. <view class="navbar-right pointer">
  25. <!-- #ifdef H5 -->
  26. <view v-if="logs.length" @click="showErrorLogs" class="menu-item debug pointer navbar-right-item-gap">
  27. <svg class="svg-icon">
  28. <use xlink:href="#icon-bug"></use>
  29. </svg>
  30. <uni-badge class="debug-badge" :text="logs.length" type="error"></uni-badge>
  31. </view>
  32. <!-- #endif -->
  33. <picker class="navbar-right-item-gap" mode="selector" :range="themes" range-key="text" :value="themeIndex" @change="changeTheme">
  34. <uni-icons type="color-filled" size="24" color="#999" />
  35. </picker>
  36. <picker class="navbar-right-item-gap" mode="selector" :range="langs" range-key="text" @change="changeLanguage" :value="langIndex">
  37. <view class="admin-icons-lang" />
  38. </picker>
  39. <view class="" style="position: relative;">
  40. <view v-show="userInfo.nickname || userInfo.username || userInfo.mobile || userInfo.email" class="navbar-user" @click="togglePopupMenu">
  41. <view class="admin-icons-user user-icon" />
  42. <view class="username ml-s"><text>{{userInfo.nickname || userInfo.username || userInfo.mobile || userInfo.email}}</text></view>
  43. <uni-icons class="arrowdown" type="arrowdown" color="#666" size="13"></uni-icons>
  44. </view>
  45. <view class="uni-mask" @click="togglePopupMenu" />
  46. <view class="navbar-menu">
  47. <template v-if="userInfo.nickname || userInfo.username || userInfo.mobile || userInfo.email">
  48. <view class="menu-item hover-highlight" @click="changePassword">
  49. <text>{{ $t("topwindow.text.changePwd") }}</text>
  50. </view>
  51. <view class="menu-item hover-highlight">
  52. <text class="logout pointer" @click="logout">{{ $t("topwindow.text.signOut") }}</text>
  53. </view>
  54. </template>
  55. <view class="popup-menu__arrow"></view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. <uni-popup ref="errorLogsPopup" type="center">
  61. <view class="modal">
  62. <scroll-view class="modal-content" scroll-y="true">
  63. <error-log class="error-table" />
  64. </scroll-view>
  65. </view>
  66. </uni-popup>
  67. <!-- 冗余代码,临时处理 uni-datetime-picker 国际化不生效的问题 -->
  68. <!-- #ifdef H5 -->
  69. <uni-datetime-picker type="date" v-show="false"></uni-datetime-picker>
  70. <!-- #endif -->
  71. </view>
  72. </template>
  73. <script>
  74. import {
  75. mapState,
  76. mapMutations
  77. } from 'vuex'
  78. import errorLog from '@/windows/components/error-log.vue'
  79. import config from '@/admin.config.js'
  80. export default {
  81. components: {
  82. errorLog
  83. },
  84. props: {
  85. navigationBarTitleText: {
  86. type: String
  87. },
  88. matchLeftWindow: {
  89. type: Boolean
  90. },
  91. showLeftWindow: {
  92. type: Boolean
  93. }
  94. },
  95. data() {
  96. return {
  97. ...config.navBar,
  98. popupMenuOpened: false,
  99. mpCapsule: 0,
  100. langIndex:0
  101. }
  102. },
  103. computed: {
  104. ...mapState('app', ['appName', 'routes', 'theme']),
  105. ...mapState('error', ['logs']),
  106. userInfo () {
  107. return this.$uniIdPagesStore.store.userInfo
  108. },
  109. themeIndex () {
  110. let i = 0
  111. this.themes.forEach((theme,index) => {
  112. if(theme.value === this.theme) i = index
  113. })
  114. return i
  115. }
  116. },
  117. mounted() {
  118. // #ifdef MP
  119. let menuButtonInfo = uni.getMenuButtonBoundingClientRect()
  120. this.mpCapsule = menuButtonInfo.width
  121. // #endif
  122. // #ifdef H5
  123. let locale = uni.getLocale();
  124. this.$nextTick(() => {
  125. let index = this.langs.findIndex((item) => {
  126. return item.lang === locale;
  127. });
  128. this.changeLanguage(index)
  129. })
  130. // #endif
  131. },
  132. methods: {
  133. ...mapMutations('app',['SET_THEME']),
  134. showErrorLogs() {
  135. if (this.popupMenuOpened) {
  136. this.popupMenuOpened = false
  137. }
  138. this.$refs.errorLogsPopup.open()
  139. },
  140. showPasswordPopup() {
  141. if (this.popupMenuOpened) {
  142. this.popupMenuOpened = false
  143. }
  144. this.$refs.passwordPopup.open()
  145. },
  146. logout() {
  147. this.popupMenuOpened = false
  148. this.$uniIdPagesStore.mutations.logout()
  149. },
  150. toggleSidebar() {
  151. if (!this.showLeftWindow) {
  152. uni.showLeftWindow()
  153. } else {
  154. uni.hideLeftWindow()
  155. }
  156. },
  157. togglePopupMenu() {
  158. this.popupMenuOpened = !this.popupMenuOpened
  159. },
  160. changePassword() {
  161. uni.navigateTo({
  162. url: '/uni_modules/uni-id-pages/pages/userinfo/change_pwd/change_pwd',
  163. complete: () => {
  164. this.popupMenuOpened = false
  165. }
  166. })
  167. },
  168. changeLanguage(e) {
  169. let index = typeof e === 'object' ? e.detail.value : e
  170. if (!index || index < 0) index = 0;
  171. const lang = this.langs[index].lang || 'zh-Hans'
  172. const platform = uni.getSystemInfoSync().platform
  173. if (platform === 'android') {
  174. uni.showToast({
  175. icon: 'error',
  176. title: '暂不支持',
  177. duration: 2000
  178. })
  179. return
  180. }
  181. this.$i18n.locale = lang
  182. this.langIndex = index;
  183. uni.setLocale(lang)
  184. },
  185. linkTo() {
  186. uni.reLaunch({
  187. url: '/'
  188. })
  189. },
  190. changeTheme(e) {
  191. const index = typeof e === 'object' ? e.detail.value : e
  192. const theme = this.themes[index].value || 'default'
  193. if(this.theme !== theme) this.SET_THEME(theme)
  194. }
  195. }
  196. }
  197. </script>
  198. <style lang="scss">
  199. .header {
  200. height: 60px;
  201. width: 100%;
  202. box-sizing: border-box;
  203. border-bottom: 1px solid darken($top-window-bg-color, 8%);
  204. background-color: $top-window-bg-color;
  205. color: $top-window-text-color;
  206. }
  207. .navbar {
  208. font-size: 14px;
  209. position: relative;
  210. height: 100%;
  211. padding: 0 20px;
  212. display: flex;
  213. justify-content: space-between;
  214. align-items: center;
  215. }
  216. .logo {
  217. min-width: 223px;
  218. display: flex;
  219. align-items: center;
  220. .logo-image {
  221. // logo宽高开发者可根据情况自行调节
  222. width: 30px;
  223. height: 30px;
  224. }
  225. .logo-text {
  226. margin-left: 8px;
  227. }
  228. }
  229. .menu-icon {
  230. width: 30px;
  231. height: 30px;
  232. line-height: 30px;
  233. }
  234. .navbar-middle,
  235. .navbar-right {
  236. flex: 1;
  237. /* #ifdef MP */
  238. margin-right: 97px;
  239. /* #endif */
  240. }
  241. .navbar-right-item-gap {
  242. margin-right: 30px;
  243. }
  244. .navbar-left {
  245. display: flex;
  246. }
  247. // 在平板以下,保持navbar-middle
  248. @media screen and (max-width: 767px) {
  249. .navbar-left {
  250. flex: 1;
  251. /* #ifdef MP */
  252. margin-right: 97px;
  253. /* #endif */
  254. }
  255. }
  256. .navbar-middle,
  257. .username {
  258. display: flex;
  259. align-items: center;
  260. overflow: hidden;
  261. text-overflow: ellipsis;
  262. white-space: nowrap;
  263. }
  264. .navbar-middle {
  265. text-align: center;
  266. }
  267. .username {
  268. max-width: 150px;
  269. }
  270. .title-text {
  271. font-size: 14px;
  272. line-height: 30px;
  273. }
  274. .navbar-menu {
  275. display: flex;
  276. }
  277. .menu-item {
  278. padding: 8px;
  279. font-size: 16px;
  280. color: #555;
  281. line-height: 1;
  282. }
  283. .debug {
  284. display: inline-block;
  285. position: relative;
  286. }
  287. .debug-badge {
  288. position: absolute;
  289. top: 5px;
  290. right: 14px;
  291. transform: translateY(-50%) translateX(100%) scale(0.8);
  292. }
  293. .arrowdown {
  294. margin-top: 4px;
  295. margin-left: 3px;
  296. }
  297. .person {
  298. margin-top: 2px;
  299. margin-right: 2px;
  300. }
  301. .navbar-right {
  302. display: flex;
  303. justify-content: flex-end;
  304. align-items: center;
  305. }
  306. .navbar-right .uni-mask {
  307. position: fixed;
  308. top: 0;
  309. left: 0;
  310. width: 100%;
  311. height: 100%;
  312. background-color: rgba(255, 255, 255, 0);
  313. z-index: 999;
  314. }
  315. .popup-menu__arrow {
  316. position: absolute;
  317. top: -6px;
  318. right: 20px;
  319. border-width: 6px;
  320. margin-right: 3px;
  321. border-top-width: 0;
  322. border-bottom-color: #ebeef5;
  323. filter: drop-shadow(0 6px 12px rgba(0, 0, 0, .1));
  324. }
  325. .popup-menu__arrow::after {
  326. content: " ";
  327. position: absolute;
  328. display: block;
  329. width: 0;
  330. height: 0;
  331. border-color: transparent;
  332. border-style: solid;
  333. border-width: 10px;
  334. top: 1px;
  335. margin-left: -10px;
  336. border-top-width: 0;
  337. border-bottom-color: #fff;
  338. }
  339. /* 大屏时,隐藏的内容 */
  340. .menu-icon,
  341. .navbar-middle,
  342. // .navbar-user,
  343. .popup-menu__arrow,
  344. .navbar-right .uni-mask {
  345. display: none;
  346. }
  347. /* 小屏,显示的内容 */
  348. .navbar-mini .menu-icon {
  349. display: block;
  350. }
  351. .navbar-user {
  352. display: flex;
  353. justify-content: center;
  354. align-items: center;
  355. }
  356. /* 小屏时,隐藏的内容 */
  357. // .navbar-mini .navbar-menu .username
  358. .navbar-mini .logo,
  359. .navbar-mini .debug,
  360. .navbar-menu {
  361. display: none;
  362. }
  363. .navbar-menu {
  364. width: 100px;
  365. flex-direction: column;
  366. align-items: center;
  367. justify-content: center;
  368. position: absolute;
  369. right: 0;
  370. /* #ifdef MP */
  371. // right: 97px;
  372. /* #endif */
  373. top: 27px;
  374. /* #ifndef H5 */
  375. // top: 85pxs: ;
  376. /* #endif */
  377. background-color: #fff;
  378. z-index: 999;
  379. padding: 10px 0;
  380. background-color: #fff;
  381. border: 1px solid #ebeef5;
  382. border-radius: 4px;
  383. box-shadow: 0 6px 12px 0 rgba(0, 0, 0, .5);
  384. }
  385. /* 小屏时,弹出下拉菜单 */
  386. .popup-menu .navbar-menu {
  387. display: flex;
  388. }
  389. .popup-menu .popup-menu__arrow,
  390. .popup-menu .navbar-right .uni-mask {
  391. display: block;
  392. }
  393. .hover-highlight:hover {
  394. color: $menu-text-color-actived;
  395. }
  396. .svg-icon {
  397. width: 1em;
  398. height: 1em;
  399. vertical-align: -.15em;
  400. fill: currentColor;
  401. overflow: hidden;
  402. }
  403. .password-popup {
  404. padding: 30px;
  405. }
  406. .language-item {
  407. font-stretch: 12px;
  408. vertical-align: baseline;
  409. text-decoration: underline;
  410. }
  411. .lang-icon {
  412. font-size: 18px;
  413. margin-top: 5px;
  414. margin-right: 30px;
  415. }
  416. .user-icon {
  417. font-size: 20px;
  418. }
  419. </style>