menus.vue 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <template>
  2. <div class="oa_menus">
  3. <div class="menus-user">
  4. <div class="userImg" @click="userImgClick">
  5. <ElAvatar :src="avatar" alt="" class="userIcon" />
  6. <div class="glBox" v-show="data?.sl">
  7. <span>司龄{{ data?.sl }}年</span>
  8. </div>
  9. <div class="userHover">
  10. <p>个人档案</p>
  11. </div>
  12. </div>
  13. <div class="userInfo">
  14. <h4>{{ userName }}</h4>
  15. <p>{{ deptName }}</p>
  16. </div>
  17. </div>
  18. <div class="menus-btns">
  19. <div class="btn" @click="toPageHandle('/mainOfficeCenter')">
  20. <img src="@/assets/imgs/OA/bjzx_icon.png" alt="" />
  21. <p>办件中心</p>
  22. <div class="tip" v-show="attendCount > 0">{{ attendCount }}</div>
  23. </div>
  24. </div>
  25. <div class="menus-tabs">
  26. <el-menu default-active="2" class="el-menu-vertical-demo">
  27. <div
  28. v-for="(item, index) in reactiveData.routes"
  29. :key="index"
  30. class="menuDiv"
  31. @mouseenter="handleMouseEnter(item, index)"
  32. @mouseleave="handleMouseLeave(item, index)"
  33. v-show="item.name != '个人档案'"
  34. >
  35. <el-menu-item @click="menuClick(item, index)" :index="String(index)">
  36. <Icon :icon="item.icon" />
  37. <span>{{ item.name }}</span>
  38. </el-menu-item>
  39. <MenusActive :menuData="menuData" v-if="mouseenterIndex == index" />
  40. </div>
  41. </el-menu>
  42. </div>
  43. </div>
  44. </template>
  45. <script setup lang="ts">
  46. import { Icon } from '@/components/Icon'
  47. import { useRouter } from 'vue-router'
  48. import { ElMessageBox } from 'element-plus'
  49. import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
  50. import avatarImg from '@/assets/imgs/avatar.gif'
  51. import { useUserStore } from '@/store/modules/user'
  52. import { useTagsViewStore } from '@/store/modules/tagsView'
  53. import MenusActive from './menusActive.vue'
  54. import { useQuery } from '@tanstack/vue-query'
  55. import { getRecordsDetail } from '@/api/oa/staffRecords'
  56. import { getAttendCount } from '@/api/oa/index'
  57. defineOptions({ name: 'Header' })
  58. const { t } = useI18n()
  59. const { wsCache } = useCache()
  60. const { push, replace, currentRoute } = useRouter()
  61. const router = useRouter()
  62. const userStore = useUserStore()
  63. const tagsViewStore = useTagsViewStore()
  64. const user = wsCache.get(CACHE_KEY.USER)
  65. console.log('user: ', user)
  66. const avatar = user.user.avatar ? user.user.avatar : avatarImg
  67. const userName = user.user.nickname ? user.user.nickname : 'Admin'
  68. const deptName = user.user.deptName ? user.user.deptName : '部门信息'
  69. const userId = user.user.id // 当前登录的编号
  70. const { data } = useQuery(['fetch-staff-detail-left', userId], async () => {
  71. return await getRecordsDetail({ userId })
  72. })
  73. /***
  74. * 根据用户ID获取待办角标
  75. */
  76. const attendCount = ref<number>(0)
  77. const initAttendCount = async () => {
  78. const result = await getAttendCount({
  79. userId: userId
  80. })
  81. if (result) {
  82. attendCount.value = result
  83. }
  84. }
  85. initAttendCount()
  86. const mouseenterIndex = ref(-1)
  87. const loginOut = () => {
  88. ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
  89. confirmButtonText: t('common.ok'),
  90. cancelButtonText: t('common.cancel'),
  91. type: 'warning'
  92. })
  93. .then(async () => {
  94. await userStore.loginOut()
  95. tagsViewStore.delAllViews()
  96. replace('/login?redirect=/index')
  97. })
  98. .catch(() => {})
  99. }
  100. const userImgClick = () => {
  101. push('/oaSystem/mineCenter')
  102. }
  103. const reactiveData: any = reactive({
  104. routes: []
  105. })
  106. const initMenus = async () => {
  107. let locals: any = localStorage.getItem('roleRouters')
  108. let roleRouters = JSON.parse(JSON.parse(locals).v)?.[0]?.children
  109. let childArr = roleRouters?.slice(0, roleRouters?.length)
  110. reactiveData.routes = childArr
  111. }
  112. const menuClick = (item: any, idx: any) => {
  113. if (item.name == '运营中心') {
  114. const url = router.resolve({
  115. path: '/oaView/marketView'
  116. })
  117. // 打开新窗口
  118. window.open(url.href)
  119. return
  120. }
  121. if (item.children == null) {
  122. push('/oaSystem/' + item.path)
  123. } else {
  124. return
  125. }
  126. }
  127. const menuData = ref()
  128. const handleMouseEnter = (item: any, index: any) => {
  129. if (item.children != null) {
  130. mouseenterIndex.value = index
  131. menuData.value = item
  132. } else {
  133. mouseenterIndex.value = -1
  134. }
  135. }
  136. const toPageHandle: (path: string) => void = (path: string) => {
  137. push({
  138. path
  139. })
  140. }
  141. const handleMouseLeave = (item: any, index: any) => {
  142. mouseenterIndex.value = -1
  143. }
  144. /** 初始化 **/
  145. onMounted(() => {
  146. initMenus()
  147. })
  148. </script>
  149. <style lang="scss" scoped>
  150. .oa_menus {
  151. width: calc(100%);
  152. height: 100%;
  153. // background: #183868;
  154. .menus-user {
  155. display: flex;
  156. width: 100%;
  157. height: 180px;
  158. padding-top: 40px;
  159. margin-bottom: 20px;
  160. border-bottom: 1px solid #5383bd;
  161. flex-wrap: wrap;
  162. justify-content: center;
  163. .userImg {
  164. position: relative;
  165. display: flex;
  166. width: 60px;
  167. height: 60px;
  168. padding: 3px;
  169. cursor: pointer;
  170. background-color: #fff;
  171. border-radius: 50%;
  172. align-items: center;
  173. justify-content: center;
  174. .userIcon {
  175. width: 100%;
  176. height: 100%;
  177. }
  178. .glBox {
  179. position: absolute;
  180. bottom: -10px;
  181. left: 50%;
  182. z-index: 1;
  183. display: flex;
  184. width: 64px;
  185. height: 18px;
  186. margin-left: -32px;
  187. background: #f9a527;
  188. border-radius: 14px;
  189. align-items: center;
  190. justify-content: center;
  191. span {
  192. font-size: 12px;
  193. color: #fff;
  194. }
  195. }
  196. .userHover {
  197. position: absolute;
  198. top: 0;
  199. left: 0;
  200. display: none;
  201. width: 100%;
  202. height: 100%;
  203. background-color: rgba($color: #000, $alpha: 30%);
  204. border-radius: 50%;
  205. align-items: center;
  206. justify-content: center;
  207. p {
  208. font-size: 10px;
  209. color: #fff;
  210. }
  211. }
  212. }
  213. .userImg:hover {
  214. .userHover {
  215. display: flex;
  216. }
  217. }
  218. .userInfo {
  219. width: 100%;
  220. margin-top: 0;
  221. h4 {
  222. margin-bottom: 5px;
  223. font-size: 18px;
  224. color: #fff;
  225. text-align: center;
  226. }
  227. p {
  228. font-size: 14px;
  229. font-weight: 400;
  230. color: #bcd1f0;
  231. text-align: center;
  232. }
  233. }
  234. }
  235. .menus-btns {
  236. width: 100%;
  237. height: 40px;
  238. padding: 0 20px;
  239. margin-bottom: 10px;
  240. position: relative;
  241. .tip {
  242. background-color: #f00;
  243. position: absolute;
  244. right: 15px;
  245. top: -10px;
  246. font-size: 12px;
  247. color: #fff;
  248. width: 22px;
  249. height: 22px;
  250. line-height: 22px;
  251. border-radius: 50%;
  252. text-align: center;
  253. }
  254. .btn {
  255. display: flex;
  256. width: 100%;
  257. height: 100%;
  258. cursor: pointer;
  259. background: #05ce9e;
  260. border-radius: 20px;
  261. align-items: center;
  262. justify-content: center;
  263. p {
  264. margin-left: 8px;
  265. font-size: 16px;
  266. font-weight: bold;
  267. color: #fff;
  268. }
  269. }
  270. }
  271. .menus-tabs {
  272. width: 100%;
  273. height: calc(100% - 250px);
  274. .menuDiv {
  275. position: relative;
  276. :deep(.el-menu-item) {
  277. justify-content: center;
  278. }
  279. }
  280. }
  281. }
  282. ::v-deep(.menus-tabs) {
  283. .el-menu {
  284. background-color: transparent;
  285. border: none;
  286. span {
  287. font-size: 16px;
  288. color: #fff;
  289. }
  290. .is-active {
  291. background-color: transparent;
  292. }
  293. .el-menu-item:hover {
  294. background-color: #113468;
  295. }
  296. }
  297. }
  298. :deep(.el-menu-item > span) {
  299. font-size: 18px !important;
  300. }
  301. :deep(.el-menu-item > .el-icon > span) {
  302. font-size: 18px !important;
  303. }
  304. </style>