user.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { reactive } from "vue";
  2. import type { UserInfoEntity } from "../types";
  3. import { forInObject, isNull, parse, storage } from "../utils";
  4. import { service } from "../service";
  5. import { router } from "../router";
  6. /**
  7. * Token类型定义
  8. * @property token 访问token
  9. * @property expire token过期时间(秒)
  10. * @property refreshToken 刷新token
  11. * @property refreshExpire 刷新token过期时间(秒)
  12. */
  13. export type Token = {
  14. token: string;
  15. expire: number;
  16. refreshToken: string;
  17. refreshExpire: number;
  18. };
  19. export class User {
  20. /**
  21. * 用户信息,响应式对象,属性结构见UserInfoEntity
  22. */
  23. info = reactive<UserInfoEntity>({});
  24. /**
  25. * 当前token,字符串或null
  26. */
  27. token: string | null = null;
  28. constructor() {
  29. // 获取本地用户信息
  30. const userInfo = storage.get("userInfo");
  31. // 获取本地token
  32. const token = storage.get("token") as string | null;
  33. // 如果token为空字符串则置为null
  34. this.token = token == "" ? null : token;
  35. // 初始化用户信息
  36. this.set(userInfo!);
  37. }
  38. /**
  39. * 获取用户信息(从服务端拉取最新信息并更新本地)
  40. * @returns Promise<void>
  41. */
  42. async get() {
  43. if (this.token != null) {
  44. await service.user.info
  45. .person({})
  46. .then((res) => {
  47. if (!isNull(res)) {
  48. this.set(res);
  49. }
  50. })
  51. .catch(() => {
  52. this.logout();
  53. });
  54. }
  55. }
  56. /**
  57. * 设置用户信息并存储到本地
  58. * @param data 用户信息对象
  59. */
  60. set(data: any) {
  61. if (isNull(data)) {
  62. return;
  63. }
  64. // 先清空原有信息
  65. this.remove();
  66. // 逐项赋值到响应式info对象
  67. forInObject(data, (value, key) => {
  68. this.info[key] = value;
  69. });
  70. // 持久化到本地存储
  71. storage.set("userInfo", data, 0);
  72. }
  73. /**
  74. * 更新用户信息(本地与服务端同步)
  75. * @param data 新的用户信息
  76. */
  77. async update(data: UserInfoEntity) {
  78. if (isNull(data) || this.isNull()) {
  79. return;
  80. }
  81. const params = { ...data };
  82. // 本地同步更新
  83. forInObject(params as any, (value, key) => {
  84. this.info[key] = value;
  85. });
  86. // 同步到服务端
  87. await service.user.info.updatePerson(params);
  88. }
  89. /**
  90. * 移除用户信息(仅清空本地响应式对象,不清除本地存储)
  91. */
  92. remove() {
  93. forInObject({ ...this.info } as any, (_, key) => {
  94. // #ifdef APP
  95. this.info[key] = null;
  96. // #endif
  97. // #ifndef APP
  98. delete this.info[key];
  99. // #endif
  100. });
  101. }
  102. /**
  103. * 判断用户信息是否为空(以id字段为准)
  104. * @returns boolean
  105. */
  106. isNull() {
  107. return isNull(this.info["id"]);
  108. }
  109. /**
  110. * 清除本地所有用户信息和token
  111. */
  112. clear() {
  113. storage.remove("userInfo");
  114. storage.remove("token");
  115. storage.remove("refreshToken");
  116. this.token = null;
  117. this.remove();
  118. }
  119. /**
  120. * 退出登录,清除所有信息并跳转到登录页
  121. */
  122. logout() {
  123. this.clear();
  124. router.login();
  125. }
  126. /**
  127. * 设置token并存储到本地
  128. * @param data Token对象
  129. */
  130. setToken(data: Token) {
  131. this.token = data.token;
  132. // 访问token,提前5秒过期,防止边界问题
  133. storage.set("token", data.token, data.expire - 5);
  134. // 刷新token,提前5秒过期
  135. storage.set("refreshToken", data.refreshToken, data.refreshExpire - 5);
  136. }
  137. /**
  138. * 刷新token(调用服务端接口,自动更新本地token)
  139. * @returns Promise<string> 新的token
  140. */
  141. refreshToken(): Promise<string> {
  142. return new Promise((resolve, reject) => {
  143. service.user.login
  144. .refreshToken({
  145. refreshToken: storage.get("refreshToken")
  146. })
  147. .then((res) => {
  148. const token = parse<Token>(res);
  149. if (token != null) {
  150. this.setToken(token);
  151. resolve(token.token);
  152. }
  153. })
  154. .catch((err) => {
  155. reject(err);
  156. });
  157. });
  158. }
  159. }
  160. /**
  161. * 单例用户对象,项目全局唯一
  162. */
  163. export const user = new User();
  164. /**
  165. * 获取用户单例实例(组合式API用法)
  166. * @returns User
  167. */
  168. export function useUser() {
  169. return user;
  170. }