user.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. /*
  2. * 登录用户
  3. *
  4. * @Author: DCCloud
  5. * @Date: 2022-09-06 20:55:09
  6. */
  7. import _ from 'lodash';
  8. import { defineStore } from 'pinia';
  9. import localKey from '/@/constants/local-storage-key-const';
  10. import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
  11. import { MENU_TYPE_ENUM } from '/@/constants/system/menu-const';
  12. import { messageApi } from '/@/api/support/message-api.js';
  13. import { smartSentry } from '/@/lib/smart-sentry.js';
  14. import { loginApi } from '/@/api/system/login-api';
  15. import { localRead, localSave, localRemove } from '/@/utils/local-util';
  16. import { autoCompleteProps } from 'ant-design-vue/lib/auto-complete';
  17. export const useUserStore = defineStore({
  18. id: 'userStore',
  19. state: () => ({
  20. token: '',
  21. //员工id
  22. employeeId: '',
  23. // 头像
  24. avatar: '',
  25. //登录名
  26. loginName: '',
  27. //姓名
  28. actualName: '',
  29. //手机号
  30. phone: '',
  31. //部门id
  32. departmentId: '',
  33. //部门名词
  34. departmentName: '',
  35. //是否需要修改密码
  36. needUpdatePwdFlag: false,
  37. //是否为超级管理员
  38. administratorFlag: true,
  39. //上次登录ip
  40. lastLoginIp: '',
  41. //上次登录ip地区
  42. lastLoginIpRegion: '',
  43. //上次登录 设备
  44. lastLoginUserAgent: '',
  45. //上次登录时间
  46. lastLoginTime: '',
  47. //左侧菜单树形结构
  48. menuTree: [],
  49. //存在页面路由的菜单集合
  50. menuRouterList: [],
  51. //是否完成menuRouter初始化
  52. menuRouterInitFlag: false,
  53. //父类菜单集合
  54. menuParentIdListMap: new Map(),
  55. // 功能点集合
  56. pointsList: [],
  57. // 标签页
  58. tagNav: null,
  59. // 缓存
  60. keepAliveIncludes: [],
  61. // 未读消息数量
  62. unreadMessageCount: 0,
  63. // 待办工作数
  64. toBeDoneCount: 0,
  65. }),
  66. getters: {
  67. getToken(state) {
  68. if (state.token) {
  69. return state.token;
  70. }
  71. return localRead(localKey.USER_TOKEN);
  72. },
  73. getNeedUpdatePwdFlag(state) {
  74. return state.needUpdatePwdFlag;
  75. },
  76. //是否初始化了 路由
  77. getMenuRouterInitFlag(state) {
  78. return state.menuRouterInitFlag;
  79. },
  80. //菜单树
  81. getMenuTree(state) {
  82. return state.menuTree;
  83. },
  84. //菜单的路由
  85. getMenuRouterList(state) {
  86. return state.menuRouterList;
  87. },
  88. //菜单的父级id
  89. getMenuParentIdListMap(state) {
  90. return state.menuParentIdListMap;
  91. },
  92. //功能点
  93. getPointList(state) {
  94. if (_.isEmpty(state.pointsList)) {
  95. let localUserPoints = localRead(localKey.USER_POINTS) || '';
  96. state.pointsList = localUserPoints ? JSON.parse(localUserPoints) : [];
  97. }
  98. return state.pointsList;
  99. },
  100. //标签页
  101. getTagNav(state) {
  102. if (_.isNull(state.tagNav)) {
  103. let localTagNav = localRead(localKey.USER_TAG_NAV) || '';
  104. state.tagNav = localTagNav ? JSON.parse(localTagNav) : [];
  105. }
  106. let tagNavList = _.cloneDeep(state.tagNav) || [];
  107. tagNavList.unshift({
  108. menuName: HOME_PAGE_NAME,
  109. menuTitle: '首页',
  110. });
  111. return tagNavList;
  112. },
  113. },
  114. actions: {
  115. autoLogin(name) {
  116. return new Promise((resolve, reject) => {
  117. loginApi.autoLogin(name).then(res => {
  118. resolve(res)
  119. }).catch(error => {
  120. reject(error)
  121. })
  122. })
  123. },
  124. setSSO(info) {
  125. return new Promise((resolve, reject) => {
  126. loginApi.login(info).then(res => {
  127. resolve(res)
  128. }).catch(error => {
  129. reject(error)
  130. })
  131. })
  132. },
  133. logout() {
  134. this.token = '';
  135. this.menuList = [];
  136. this.tagNav = [];
  137. this.unreadMessageCount = 0;
  138. localRemove(localKey.USER_TOKEN);
  139. localRemove(localKey.USER_POINTS);
  140. localRemove(localKey.USER_TAG_NAV);
  141. localRemove('loginFrom');
  142. },
  143. // 查询未读消息数量
  144. async queryUnreadMessageCount() {
  145. try {
  146. let result = await messageApi.queryUnreadCount();
  147. this.unreadMessageCount = result.data;
  148. } catch (e) {
  149. smartSentry.captureError(e);
  150. }
  151. },
  152. async queryToBeDoneList() {
  153. try {
  154. let localToBeDoneList = localRead(localKey.TO_BE_DONE);
  155. if (localToBeDoneList) {
  156. this.toBeDoneCount = JSON.parse(localToBeDoneList).filter((e) => !e.doneFlag).length;
  157. }
  158. } catch (err) {
  159. smartSentry.captureError(err);
  160. }
  161. },
  162. //设置登录信息
  163. setUserLoginInfo(data) {
  164. // 用户基本信息
  165. this.token = data.token;
  166. this.employeeId = data.employeeId;
  167. this.avatar = data.avatar;
  168. this.loginName = data.loginName;
  169. this.actualName = data.actualName;
  170. this.phone = data.phone;
  171. this.departmentId = data.departmentId;
  172. this.departmentName = data.departmentName;
  173. this.needUpdatePwdFlag = data.needUpdatePwdFlag;
  174. this.administratorFlag = data.administratorFlag;
  175. this.lastLoginIp = data.lastLoginIp;
  176. this.lastLoginIpRegion = data.lastLoginIpRegion;
  177. this.lastLoginUserAgent = data.lastLoginUserAgent;
  178. this.lastLoginTime = data.lastLoginTime;
  179. //菜单权限
  180. this.menuTree = buildMenuTree(data.menuList);
  181. //拥有路由的菜单
  182. this.menuRouterList = data.menuList.filter((e) => e.path || e.frameUrl);
  183. //父级菜单集合
  184. this.menuParentIdListMap = buildMenuParentIdListMap(this.menuTree);
  185. //功能点
  186. this.pointsList = data.menuList.filter((menu) => menu.menuType === MENU_TYPE_ENUM.POINTS.value && menu.visibleFlag && !menu.disabledFlag);
  187. // 获取用户未读消息
  188. this.queryUnreadMessageCount();
  189. // 获取待办工作数
  190. this.queryToBeDoneList();
  191. },
  192. setToken(token) {
  193. this.token = token;
  194. },
  195. //设置标签页
  196. setTagNav(route, from) {
  197. if (_.isNull(this.tagNav)) {
  198. let localTagNav = localRead(localKey.USER_TAG_NAV) || '';
  199. this.tagNav = localTagNav ? JSON.parse(localTagNav) : [];
  200. }
  201. // name唯一标识
  202. let name = route.name;
  203. if (!name || name === HOME_PAGE_NAME || name === 'error-403' || name === 'error-404') {
  204. return;
  205. }
  206. let findTag = (this.tagNav || []).find((e) => e.menuName === name);
  207. if (findTag) {
  208. // @ts-ignore
  209. findTag.fromMenuName = from.name;
  210. findTag.fromMenuQuery = from.query;
  211. for (const i of this.tagNav) {
  212. if (i.menuName === name) {
  213. i.menuQuery = route.query
  214. }
  215. }
  216. } else {
  217. // @ts-ignore
  218. this.tagNav.push({
  219. // @ts-ignore
  220. menuName: name,
  221. // @ts-ignore
  222. menuTitle: route.meta.title,
  223. menuQuery: route.query,
  224. // @ts-ignore
  225. fromMenuName: from.name,
  226. fromMenuQuery: from.query,
  227. });
  228. }
  229. localSave(localKey.USER_TAG_NAV, JSON.stringify(this.tagNav));
  230. },
  231. //关闭标签页
  232. closeTagNav(menuName, closeAll) {
  233. if (_.isEmpty(this.getTagNav)) return;
  234. if (closeAll && !menuName) {
  235. this.tagNav = [];
  236. this.clearKeepAliveIncludes();
  237. } else {
  238. let findIndex = (this.tagNav || []).findIndex((e) => e.menuName === menuName);
  239. if (closeAll) {
  240. if (findIndex === -1) {
  241. this.tagNav = [];
  242. this.clearKeepAliveIncludes();
  243. } else {
  244. let tagNavElement = (this.tagNav || [])[findIndex];
  245. this.tagNav = [tagNavElement];
  246. this.clearKeepAliveIncludes(tagNavElement.menuName);
  247. }
  248. } else {
  249. (this.tagNav || []).splice(findIndex, 1);
  250. this.deleteKeepAliveIncludes(menuName);
  251. }
  252. }
  253. localSave(localKey.USER_TAG_NAV, JSON.stringify(this.tagNav));
  254. },
  255. //关闭页面
  256. closePage(route, router, path) {
  257. if (!this.getTagNav || _.isEmpty(this.getTagNav)) return;
  258. if (path) {
  259. router.push({ path });
  260. } else {
  261. // 寻找tagNav
  262. let index = this.getTagNav.findIndex((e) => e.menuName === route.name);
  263. if (index === -1) {
  264. router.push({ name: HOME_PAGE_NAME });
  265. } else {
  266. let tagNav = this.getTagNav[index];
  267. if (tagNav.fromMenuName && this.getTagNav.some((e) => e.menuName === tagNav.fromMenuName)) {
  268. router.push({ name: tagNav.fromMenuName, query: tagNav.fromMenuQuery });
  269. } else {
  270. // 查询左侧tag
  271. let leftTagNav = this.getTagNav[index - 1];
  272. router.push({ name: leftTagNav.menuName, query: leftTagNav.menuQuery });
  273. }
  274. }
  275. }
  276. this.closeTagNav(route.name, false);
  277. },
  278. // 加入缓存
  279. pushKeepAliveIncludes(val) {
  280. if (!val) {
  281. return;
  282. }
  283. if (!this.keepAliveIncludes) {
  284. this.keepAliveIncludes = [];
  285. }
  286. if (this.keepAliveIncludes.length < 30) {
  287. let number = this.keepAliveIncludes.findIndex((e) => e === val);
  288. if (number === -1) {
  289. this.keepAliveIncludes.push(val);
  290. }
  291. }
  292. },
  293. // 删除缓存
  294. deleteKeepAliveIncludes(val) {
  295. if (!this.keepAliveIncludes || !val) {
  296. return;
  297. }
  298. let number = this.keepAliveIncludes.findIndex((e) => e === val);
  299. if (number !== -1) {
  300. this.keepAliveIncludes.splice(number, 1);
  301. }
  302. },
  303. // 清空缓存
  304. clearKeepAliveIncludes(val) {
  305. if (!val || !this.keepAliveIncludes.includes(val)) {
  306. this.keepAliveIncludes = [];
  307. return;
  308. }
  309. this.keepAliveIncludes = [val];
  310. },
  311. },
  312. });
  313. /**
  314. * 构建菜单父级集合
  315. */
  316. function buildMenuParentIdListMap(menuTree) {
  317. let menuParentIdListMap = new Map();
  318. recursiveBuildMenuParentIdListMap(menuTree, [], menuParentIdListMap);
  319. return menuParentIdListMap;
  320. }
  321. function recursiveBuildMenuParentIdListMap(menuList, parentMenuList, menuParentIdListMap) {
  322. for (const e of menuList) {
  323. // 顶级parentMenuList清空
  324. if (e.parentId === 0) {
  325. parentMenuList = [];
  326. }
  327. let menuIdStr = e.menuId.toString();
  328. let cloneParentMenuList = _.cloneDeep(parentMenuList);
  329. if (!_.isEmpty(e.children) && e.menuName) {
  330. // 递归
  331. cloneParentMenuList.push({ name: menuIdStr, title: e.menuName });
  332. recursiveBuildMenuParentIdListMap(e.children, cloneParentMenuList, menuParentIdListMap);
  333. } else {
  334. menuParentIdListMap.set(menuIdStr, cloneParentMenuList);
  335. }
  336. }
  337. }
  338. /**
  339. * 构建菜单树
  340. *
  341. * @param menuList
  342. * @returns
  343. */
  344. function buildMenuTree(menuList) {
  345. //1 获取所有 有效的 目录和菜单
  346. let catalogAndMenuList = menuList.filter((menu) => menu.menuType !== MENU_TYPE_ENUM.POINTS.value && menu.visibleFlag && !menu.disabledFlag);
  347. //2 获取顶级目录
  348. let topCatalogList = catalogAndMenuList.filter((menu) => menu.parentId === 0);
  349. for (const topCatalog of topCatalogList) {
  350. buildMenuChildren(topCatalog, catalogAndMenuList);
  351. }
  352. return topCatalogList;
  353. }
  354. function buildMenuChildren(menu, allMenuList) {
  355. let children = allMenuList.filter((e) => e.parentId === menu.menuId);
  356. if (children.length === 0) {
  357. return;
  358. }
  359. menu.children = children;
  360. for (const item of children) {
  361. buildMenuChildren(item, allMenuList);
  362. }
  363. }