menus.vue 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. <template>
  2. <div class="oa_menus">
  3. <div class="menus-user">
  4. <div class="userImg" @click="userImgClick">
  5. <ElAvatar :src="user.user.avatar ?? avatarImg" 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="toMainOfficeCenter()">
  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.visible && 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. <span
  39. class="project_corner"
  40. v-if="['个人中心'].includes(item.name) && projectCorner > 0"
  41. >
  42. {{ projectCorner }}
  43. </span>
  44. </el-menu-item>
  45. <MenusActive :menuData="menuData" v-if="mouseenterIndex == index" />
  46. </div>
  47. </el-menu>
  48. <div class="ai-btn">
  49. <img class="ai-tip" :src="AITip" alt="" />
  50. <img :src="AIBtn" alt="" class="robot" @click="handleGoToAi" />
  51. </div>
  52. </div>
  53. </div>
  54. </template>
  55. <script setup lang="ts">
  56. import { Icon } from '@/components/Icon'
  57. import { useRouter } from 'vue-router'
  58. import { ElMessageBox } from 'element-plus'
  59. import avatarImg from '@/assets/imgs/avatar.gif'
  60. import { useUserStore } from '@/store/modules/user'
  61. import { useTagsViewStore } from '@/store/modules/tagsView'
  62. import MenusActive from './menusActive.vue'
  63. import { useQuery } from '@tanstack/vue-query'
  64. import { getRecordsDetail } from '@/api/oa/staffRecords'
  65. import { getAttendCount } from '@/api/oa/index'
  66. import subscribe from '@/utils/Subscribe'
  67. import request from '@/config/axios'
  68. import { useUserStoreWithOut } from '@/store/modules/user'
  69. import AIBtn from '@/assets/imgs/ai/robot.png'
  70. import AITip from '@/assets/imgs/ai/aiTip.png'
  71. defineOptions({ name: 'Header' })
  72. const { t } = useI18n()
  73. const { push, replace } = useRouter()
  74. const router = useRouter()
  75. const tagsViewStore = useTagsViewStore()
  76. const userStore = useUserStoreWithOut()
  77. const user = userStore.$state
  78. const userName = user.user.nickname ? user.user.nickname : 'Admin'
  79. const deptName = user.user.deptName ? user.user.deptName : '部门信息'
  80. const userId = user.user.id // 当前登录的编号
  81. const { data } = useQuery(['fetch-staff-detail-left', userId], async () => {
  82. return await getRecordsDetail({ userId })
  83. })
  84. //个人中心角标(项目产值待审核)
  85. const projectCorner = ref<number>(0)
  86. const getProjectCheckNum = async () => {
  87. const result: any = await request.get(
  88. {
  89. url: '/projectReport/check-num'
  90. },
  91. '/business'
  92. )
  93. projectCorner.value = result
  94. }
  95. getProjectCheckNum()
  96. /***
  97. * 根据用户ID获取待办角标
  98. */
  99. const attendCount = ref<number>(0)
  100. const initAttendCount = async () => {
  101. const result = await getAttendCount({
  102. userId: userId
  103. })
  104. if (result) {
  105. attendCount.value = result
  106. }
  107. }
  108. initAttendCount()
  109. subscribe.on('updateHandleCenterCorner', () => {
  110. //同步更新办件中心角标
  111. initAttendCount()
  112. })
  113. const mouseenterIndex = ref(-1)
  114. const loginOut = () => {
  115. ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
  116. confirmButtonText: t('common.ok'),
  117. cancelButtonText: t('common.cancel'),
  118. type: 'warning'
  119. })
  120. .then(async () => {
  121. await userStore.loginOut()
  122. tagsViewStore.delAllViews()
  123. replace('/login?redirect=/index')
  124. })
  125. .catch(() => {
  126. })
  127. }
  128. const handleGoToAi = (): void => {
  129. push('/OaSystem/aiQA')
  130. }
  131. const userImgClick = () => {
  132. push('/oaSystem/mineCenter')
  133. }
  134. const reactiveData: any = reactive({
  135. routes: []
  136. })
  137. const initMenus = async () => {
  138. let locals: any = localStorage.getItem('roleRouters')
  139. let roleRouters = JSON.parse(JSON.parse(locals).v)?.[0]?.children
  140. let childArr = roleRouters?.slice(0, roleRouters?.length)
  141. reactiveData.routes = childArr
  142. }
  143. const menuClick = (item: any, idx: any) => {
  144. if (item.name == '运营中心') {
  145. const url = router.resolve({
  146. path: '/oaView/marketView'
  147. })
  148. // 打开新窗口
  149. window.open(url.href)
  150. return
  151. }
  152. if (item.children == null) {
  153. push('/oaSystem/' + item.path)
  154. } else {
  155. return
  156. }
  157. }
  158. const menuData = ref()
  159. const handleMouseEnter = (item: any, index: any) => {
  160. if (item.children != null) {
  161. mouseenterIndex.value = index
  162. menuData.value = item
  163. } else {
  164. mouseenterIndex.value = -1
  165. }
  166. }
  167. const toMainOfficeCenter = () => {
  168. router.push({
  169. path: '/mainOfficeCenter'
  170. })
  171. }
  172. const handleMouseLeave = (item: any, index: any) => {
  173. mouseenterIndex.value = -1
  174. }
  175. /** 初始化 **/
  176. onMounted(() => {
  177. initMenus()
  178. })
  179. </script>
  180. <style lang="scss" scoped>
  181. .oa_menus {
  182. width: calc(100%);
  183. height: 100%;
  184. // background: #183868;
  185. .menus-user {
  186. display: flex;
  187. width: 100%;
  188. height: 180px;
  189. padding-top: 40px;
  190. margin-bottom: 20px;
  191. border-bottom: 1px solid #5383bd;
  192. flex-wrap: wrap;
  193. justify-content: center;
  194. .userImg {
  195. position: relative;
  196. display: flex;
  197. width: 60px;
  198. height: 60px;
  199. padding: 3px;
  200. cursor: pointer;
  201. background-color: #fff;
  202. border-radius: 50%;
  203. align-items: center;
  204. justify-content: center;
  205. .userIcon {
  206. width: 100%;
  207. height: 100%;
  208. }
  209. .glBox {
  210. position: absolute;
  211. bottom: -10px;
  212. left: 50%;
  213. z-index: 1;
  214. display: flex;
  215. width: 64px;
  216. height: 18px;
  217. margin-left: -32px;
  218. background: #f9a527;
  219. border-radius: 14px;
  220. align-items: center;
  221. justify-content: center;
  222. span {
  223. font-size: 12px;
  224. color: #fff;
  225. }
  226. }
  227. .userHover {
  228. position: absolute;
  229. top: 0;
  230. left: 0;
  231. display: none;
  232. width: 100%;
  233. height: 100%;
  234. background-color: rgba($color: #000, $alpha: 30%);
  235. border-radius: 50%;
  236. align-items: center;
  237. justify-content: center;
  238. p {
  239. font-size: 10px;
  240. color: #fff;
  241. }
  242. }
  243. }
  244. .userImg:hover {
  245. .userHover {
  246. display: flex;
  247. }
  248. }
  249. .userInfo {
  250. width: 100%;
  251. margin-top: 0;
  252. h4 {
  253. margin-bottom: 5px;
  254. font-size: 18px;
  255. color: #fff;
  256. text-align: center;
  257. }
  258. p {
  259. font-size: 14px;
  260. font-weight: 400;
  261. color: #bcd1f0;
  262. text-align: center;
  263. }
  264. }
  265. }
  266. .project_corner {
  267. background-color: #f00;
  268. position: absolute;
  269. right: 25px;
  270. top: 10px;
  271. font-size: 12px;
  272. color: #fff;
  273. width: 22px;
  274. height: 22px;
  275. line-height: 22px;
  276. border-radius: 50%;
  277. font-size: 14px !important;
  278. text-align: center;
  279. }
  280. .menus-btns {
  281. width: 100%;
  282. height: 40px;
  283. padding: 0 20px;
  284. margin-bottom: 10px;
  285. position: relative;
  286. .tip {
  287. background-color: #f00;
  288. position: absolute;
  289. right: 15px;
  290. top: -10px;
  291. font-size: 12px;
  292. color: #fff;
  293. width: 22px;
  294. height: 22px;
  295. line-height: 22px;
  296. border-radius: 50%;
  297. text-align: center;
  298. }
  299. .btn {
  300. display: flex;
  301. width: 100%;
  302. height: 100%;
  303. cursor: pointer;
  304. background: #05ce9e;
  305. border-radius: 20px;
  306. align-items: center;
  307. justify-content: center;
  308. p {
  309. margin-left: 8px;
  310. font-size: 16px;
  311. font-weight: bold;
  312. color: #fff;
  313. }
  314. }
  315. }
  316. .menus-tabs {
  317. width: 100%;
  318. height: calc(100% - 250px);
  319. position: relative;
  320. .ai-btn {
  321. position: absolute;
  322. bottom: 30px;
  323. left: 50%;
  324. transform: translateX(-50%);
  325. z-index: 9;
  326. cursor: pointer;
  327. .ai-tip {
  328. width: 60px;
  329. height: 22px;
  330. position: absolute;
  331. bottom: 80px;
  332. right: -20px;
  333. }
  334. .robot{
  335. width: 85px;
  336. height: 102px;
  337. }
  338. }
  339. .menuDiv {
  340. position: relative;
  341. :deep(.el-menu-item) {
  342. justify-content: center;
  343. }
  344. }
  345. }
  346. }
  347. ::v-deep(.menus-tabs) {
  348. .el-menu {
  349. background-color: transparent;
  350. border: none;
  351. span {
  352. font-size: 16px;
  353. color: #fff;
  354. }
  355. .is-active {
  356. background-color: transparent;
  357. }
  358. .el-menu-item:hover {
  359. background-color: #113468;
  360. }
  361. }
  362. }
  363. :deep(.el-menu-item > span) {
  364. font-size: 18px !important;
  365. }
  366. :deep(.el-menu-item > .el-icon > span) {
  367. font-size: 18px !important;
  368. }
  369. </style>